SQL选择由外键链接的其他表中的条目

时间:2013-09-21 20:54:58

标签: mysql sql database

我重新设计了我的数据库结构,使用PRIMARY和FOREIGN KEY将我的3个表中的条目链接在一起,我在尝试编写查询以在另一个表中给定数据的一个表中选择数据时遇到问题。以下是我的3个CREATE TABLE语句的示例:

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美元的用户的所有用户名。所有用户名都存储在播放器表中,该表链接到帐户表并链接到购买表。这是设计此关系数据库的最佳方式吗?如果是这样,我将如何运行类似于上面示例的查询?

我能够根据用户名获得所有用户购买历史记录,但我使用2个子查询来完成...获取该数据应该比这更容易! 以下是我为了让所有玩家购买数据而运行的SELECT查询:

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

此外,当我尝试使用类似'players.username'的内容引用其他表时,我收到一条错误消息,指出该列不存在...

我感谢任何帮助!谢谢!

1 个答案:

答案 0 :(得分:7)

我认为你的设计还可以。玩家和帐户之间的关系是一对多而不是一对一,因为这样,您可以有两个元组引用单个玩家。

我会将您需要的查询编写为:

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);

正如Sam建议的那样,我添加了DISTINCT以避免在用户多次购买时重复ID和用户名。 注意这里的id是为了避免重复用户名之间的混淆。