2014-07-22 37 views
1

我在我的代码中有以下表结构,我试图从用户表中提取用户名和名称字段,但查询当前只能从from_user_id数据中提取。我如何修改这个,以便我得到两个单独的列,列出to_user_id和from_user_id的用户名和名称?如何在MySql中连接2列?

SELECT f.id, from_user_id, to_user_id, STATUS, u.username, u.name 
FROM friend f 
left JOIN users u ON f.from_user_id = u.id 
WHERE f.id IN(
SELECT source_id 
FROM notification 
WHERE user_id = 5 AND notification_read = 1) 

用户表:

CREATE TABLE `users` (
    `id` BIGINT(20) NOT NULL AUTO_INCREMENT, 
    `username` VARCHAR(60) NOT NULL, 
    `password` VARCHAR(64) NOT NULL, 
    `enabled` TINYINT(4) NOT NULL DEFAULT '1', 
    `email` VARCHAR(100) NOT NULL, 
    `name` VARCHAR(100) NOT NULL, 
    `created_on` DATETIME NOT NULL, 
    `role` VARCHAR(50) NULL DEFAULT 'ROLE_USER', 
    PRIMARY KEY (`id`), 
    UNIQUE INDEX `username` (`username`) 
) 

和朋友表:

CREATE TABLE `friend` (
    `id` BIGINT(20) NOT NULL AUTO_INCREMENT, 
    `from_user_id` BIGINT(20) NOT NULL, 
    `to_user_id` BIGINT(20) NOT NULL, 
    `status` INT(2) NOT NULL, 
    `requested_date` DATETIME NULL DEFAULT NULL, 
    `accepted_date` DATETIME NULL DEFAULT NULL, 
    PRIMARY KEY (`id`), 
    INDEX `from_user_id` (`from_user_id`), 
    INDEX `to_user_id` (`to_user_id`) 
) 

和通知表:

CREATE TABLE `notification` (
    `id` BIGINT(20) NOT NULL AUTO_INCREMENT, 
    `user_id` BIGINT(20) NOT NULL, 
    `activity_type` TINYINT(4) NOT NULL, 
    `source_id` BIGINT(20) NOT NULL, 
    `parent_id` BIGINT(20) NULL DEFAULT NULL, 
    `parent_type` TINYINT(4) NULL DEFAULT NULL, 
    `notification_read` TINYINT(4) NOT NULL DEFAULT '0', 
    `created_on` DATETIME NOT NULL, 
    PRIMARY KEY (`id`), 
    INDEX `user_id` (`user_id`), 
    INDEX `created_on` (`created_on`) 
) 

回答

1

您需要执行加入针对users - 针对朋友关系的每一方,并针对users从这两个连接中的SELECT列表中包含适当的列。

SELECT 
    f.id, 
    from_user_id, 
    to_user_id, 
    STATUS, 
    -- uf is an alias for the "from" user 
    -- You must alias the columns to distinguish them 
    uf.username AS from_username, 
    uf.name AS from_name, 
    -- ut is an alias for the "to" user 
    ut.username AS to_username, 
    ut.name AS to_name 
FROM 
    friend f 
    -- Join first for the from user info 
    LEFT JOIN users uf ON f.from_user_id = uf.id 
    -- Join again for the to user info 
    LEFT JOIN users ut ON f.to_user_id = ut.id 
WHERE f.id IN(
    SELECT source_id 
    FROM notification 
    WHERE user_id = 5 AND notification_read = 1 
) 

进一步的说明...你可以代替一个INNER JOINnotification代替IN()子查询,你可能会获得更好的性能。

SELECT 
    DISTINCT /* needed assuming multiple notification.source_id per f.id */ 
    f.id, 
    from_user_id, 
    to_user_id, 
    STATUS, 
    uf.username AS from_username, 
    uf.name AS from_name, 
    ut.username AS to_username, 
    ut.name AS to_name 
FROM 
    friend f 
    LEFT JOIN users uf ON f.from_user_id = uf.id 
    LEFT JOIN users ut ON f.to_user_id = ut.id 
    -- Join notification instead of the IN() subquery 
    INNER JOIN notification 
    ON f.id = notification.source_id 
    AND notification.user_id = 5 
    AND notification_read = 1 
+0

注意最后的内部连接,极有可能在'notification'表中存在多个'f.id'的source_id。如果是这种情况..也许EXISTS会表现得更好。 – Arth

+0

@Arth确实很好。如果存在多个'source_id',添加一个'DISTINCT'可以纠正潜在的重复。 –

+0

确实如此,看看哪个表现更好会很有趣。 – Arth