2013-09-21 3 views
11

Я изменил структуру своей базы данных, чтобы использовать PRIMARY и FOREIGN KEYs, чтобы связать записи в моих трех таблицах вместе, и у меня возникают проблемы с попыткой написать запросы для выбора данных в одной таблице данные в другой таблице. Вот пример из моего 3 CREATE TABLE заявления:SQL-выбор записей в другой таблице, связанной внешними ключами

CREATE TABLE IF NOT EXISTS players (
    id INT(10) NOT NULL AUTO_INCREMENT, 
    username VARCHAR(16) NOT NULL, 
    uuid VARCHAR(200) NOT NULL DEFAULT 0, 
    joined TIMESTAMP DEFAULT 0, 
    last_seen TIMESTAMP DEFAULT 0, 
    PRIMARY KEY (id) 
); 

/* ^
    One | 
     To 
     | One 
     v 
*/ 

CREATE TABLE IF NOT EXISTS accounts (
    id INT(10) NOT NULL AUTO_INCREMENT, 
    account_id INT(10) NOT NULL, 
    pass_hash VARCHAR(200) NOT NULL, 
    pass_salt VARCHAR(200) NOT NULL, 
    created BIGINT DEFAULT 0, 
    last_log_on BIGINT DEFAULT 0, 
    PRIMARY KEY (id), 
    FOREIGN KEY (account_id) REFERENCES players(id) ON DELETE CASCADE 
) ENGINE=InnoDB; 

/* ^
    One | 
     To 
     | Many 
     v 
*/ 

CREATE TABLE IF NOT EXISTS purchases (
    id INT(10) NOT NULL AUTO_INCREMENT, 
    account_id INT(10) NOT NULL, 
    status VARCHAR(20) NOT NULL, 
    item INT NOT NULL, 
    price DOUBLE DEFAULT 0, 
    description VARCHAR(200) NOT NULL, 
    buyer_name VARCHAR(200) NOT NULL, 
    buyer_email VARCHAR(200) NOT NULL, 
    transaction_id VARCHAR(200) NOT NULL, 
    payment_type VARCHAR(20) NOT NULL, 
    PRIMARY KEY (id), 
    FOREIGN KEY (account_id) REFERENCES accounts(account_id) ON DELETE CASCADE 
) ENGINE=InnoDB;

Скажет, например, я хочу, чтобы выбрать все имена пользователей, которые приобрели что-либо большее, чем $ 30. Все имена пользователей хранятся в таблице игроков, которая привязана к таблице учетных записей и привязана к таблице покупок. Это лучший способ создать эту реляционную базу данных? Если да, как бы я запускал запросы, подобные приведенному выше примеру?

Мне удалось получить всю историю покупок пользователей, учитывая их имя пользователя, но я сделал это с двумя подзапросами ... Получение этих данных должно быть проще! Вот ВЫБРАТЬ запрос я побежал, чтобы получить все из игроков приобрести данные:

SELECT * 
FROM purchases 
WHERE account_id = (SELECT id FROM accounts WHERE account_id = (SELECT id FROM players WHERE username = 'username'));

Кроме того, когда я пытаюсь сделать ссылки на другие таблицы, используя что-то вроде «players.username», я получаю сообщение об ошибке говорящее что колонка не существует ...

Я ценю любую помощь! Благодаря!

+3

http://en.wikipedia.org/wiki/Join_%28SQL%29 – Sam

+1

@Sam Вау, я должен был знать, что объединения связаны с этим! Я должен был сделать больше исследований! Спасибо за ссылку! И я смог сделать запрос для примера, который я предоставил в вопросе, используя внутренние соединения: SELECT username ОТ игроков INNER JOIN accounts ON players.id = accounts.account_id INNER JOIN покупки ON accounts.id = покупки.account_id WHERE purchase.price> = 30; –

+0

Ну, все сразу начали :). Этот запрос сам по себе выглядит правильным, однако вы просто присоединяетесь к одной покупке *, поэтому вы можете пропустить покупки с ценой> 30 (я предполагаю отношение от одного до многих). Подзапрос на этих покупках будет делать это, в качестве альтернативы, вы можете использовать правильные внешние соединения и отличные или просто поместить условие «цена> 30» в предикат соединения для покупок. – Sam

ответ

5

Ваш дизайн в порядке, на мой взгляд. Соотношение между игроками и учетной записью является «один ко многим», а не «один к одному» с этого момента, вы можете иметь два кортежа, ссылающихся на одного игрока.

Я хотел бы написать запрос, нужно, как:

SELECT DISTINCT p.id, p.username 
FROM players p INNER JOIN accounts a ON (p.id = a.account_id) 
       INNER JOIN purchases pc ON (a.id = pc.account_id) 
WHERE (pc.price > 30); 

Как предложил Сэм, я добавил DISTINCT, чтобы избежать повторений идентификатора и имени пользователя в случае, если пользователь уже несколько покупок. Обратите внимание, что идентификатор здесь, чтобы избежать путаницы между повторяющимися именами пользователей.

+0

Это зависит от вас. В принципе, хорошо иметь фактический ответ на принятие. Однако этот запрос не возвращает правильный результат, если у игрока несколько покупок или учетных записей. – Sam

+1

Я принял его, поэтому вы должны его сохранить! : p –

+3

Оживленный, как и ожидалось от ласки xD. Я не здесь, чтобы украсть ответ, просто попробуйте это: 'SELECT p.username ОТ игроков p INNER JOIN accounts a ON (p.id = a.account_id) INNER JOIN покупает pc ON (a.id = pc .account_id и pc.price> 30) ; '... Мы говорим о деньгах здесь :) – Sam

Смежные вопросы