用户有很多计算机,计算机在不同的表中有很多属性,最好的方法是JOIN?

时间:2012-10-29 09:54:06

标签: mysql sql join many-to-many

我有一个供用户使用的表格:

USERS:
ID   |   NAME  | 
----------------
1    |   JOHN  |
2    |   STEVE |

计算机表:

COMPUTERS:
ID   |   USER_ID |
------------------
13   |     1     |
14   |     1     |

处理器表:

PROCESSORS:
ID   |   NAME             |
---------------------------
27   |   PROCESSOR TYPE 1 |
28   |   PROCESSOR TYPE 2 |

和硬盘表:

HARDDRIVES:
ID   |   NAME              |
---------------------------|
35   |   HARDDRIVE TYPE 25 |
36   |   HARDDRIVE TYPE 90 |

每台计算机可以有不同属性表(处理器,硬盘等)的许多属性,所以我有这样的交集表,将属性链接到计算机:

COMPUTER_PROCESSORS:
C_ID |  P_ID  |
--------------|
13   |   27   |
13   |   28   |
14   |   27   |

COMPUTER_HARDDRIVES:
C_ID |  H_ID  |
--------------|
13   |   35   |
因此,具有id 1的用户JOHN拥有计算机13和14.计算机13具有处理器27和28,并且计算机13具有硬驱动器35.计算机14具有处理器27并且没有硬盘驱动器。

鉴于用户的ID,我想检索该用户计算机的每个计算机属性的列表。

我找到了一个给我一些结果的查询:

SELECT computers.id, processors.id AS p_id, processors.name AS p_name, harddrives.id AS h_id, harddrives.name AS h_name,
FROM computers

JOIN computer_processors ON (computer_processors.c_id = computers.id) 
JOIN processors ON (processors.id = computer_processors.p_id)

JOIN computer_harddrives ON (computer_harddrives.c_id = computers.id) 
JOIN harddrives ON (harddrives.id = computer_harddrives.h_id)

WHERE computers.user_id = 1

结果:

ID   | P_ID | P_NAME           | H_ID | H_NAME            |
-----------------------------------------------------------
13   |  27  | PROCESSOR TYPE 1 |  35  | HARDDRIVE TYPE 25 |
13   |  28  | PROCESSOR TYPE 2 |  35  | HARDDRIVE TYPE 25 |

但这有几个问题......

  1. 计算机14没有出现,因为它没有硬盘。 我可以以某种方式进行外部联接以确保所有计算机都显示出来,即使它们没有某些属性吗?

  2. 计算机13出现两次,两者都有相同的硬盘监听。当更多属性被添加到计算机(例如3块ram)时,为该计算机返回的行数变得非常大,并且它必须在应用程序代码中对结果进行排序。 我可以以某种方式进行查询,将两个返回的行组合在一起吗?或者在第二行的h_name列中返回NULL的查询,以便返回的所有值都是唯一的?

  3. 编辑: 我想要回归的是:

    ID   | P_ID | P_NAME           | H_ID | H_NAME            |
    -----------------------------------------------------------
    13   |  27  | PROCESSOR TYPE 1 |  35  | HARDDRIVE TYPE 25 |
    13   |  28  | PROCESSOR TYPE 2 |  35  | NULL              |
    14   |  27  | PROCESSOR TYPE 1 | NULL | NULL              |
    

    或者任何可以轻松将其变成像这样的数组的结果

    [13] =>
        [P_NAME] =>
             [0] => PROCESSOR TYPE 1
             [1] => PROCESSOR TYPE 2
        [H_NAME] =>
             [0] => HARDDRIVE TYPE 25
    
    
    [14] =>
        [P_NAME] =>
             [0] => PROCESSOR TYPE 1
    

4 个答案:

答案 0 :(得分:4)

使用LEFT JOIN代替INNER JOIN。这两个连接彼此不同。 INNER JOIN(您当前使用的 )仅返回表格两侧至少有一个匹配的记录。这就是为什么computer 14不应该因为它在表COMPUTER_HARDDRIVES上没有匹配的原因。另一方面,LEFT JOIN返回左侧表中的所有记录,无论表格的另一侧是否匹配。

SELECT  a.ID AS UserID,
        a.Name as UserName,
        b.ID as ComputerID,
        d.ID as ProcessorID,
        d.Name as ProcessorName,
        f.ID as HardDriveID,
        f.name as HardDriveName
FROM    users a
        INNER JOIN computers b
            ON a.ID = b.user_ID
        LEFT JOIN computer_processors c
            ON b.ID = c.C_ID
        LEFT JOIN PROCESSORS d
            ON c.p_ID = d.ID
        LEFT JOIN COMPUTER_HARDDRIVES e
            ON b.ID = e.c_ID
        LEFT JOIN HARDDRIVE f
            ON e.h_ID = f.ID
WHERE   a.ID = 1

由于您希望将行组合在一起,因此您可以利用GROUP_CONCAT()函数。基本上,它的作用是将列的值组合成逗号分隔值

SELECT  a.ID AS UserID,
        a.Name as UserName,
        b.ID as ComputerID,
        GROUP_CONCAT(DISTINCT d.ID) as ProcessorID,
        GROUP_CONCAT(DISTINCT d.Name) as ProcessorName,
        GROUP_CONCAT(DISTINCT f.ID) as HardDriveID,
        GROUP_CONCAT(DISTINCT f.name) as HardDriveName
FROM    users a
        INNER JOIN computers b
            ON a.ID = b.user_ID
        LEFT JOIN computer_processors c
            ON b.ID = c.C_ID
        LEFT JOIN PROCESSORS d
            ON c.p_ID = d.ID
        LEFT JOIN COMPUTER_HARDDRIVES e
            ON b.ID = e.c_ID
        LEFT JOIN HARDDRIVE f
            ON e.h_ID = f.ID
WHERE   a.ID = 1
GROUP BY UserID, UserName, ComputerID

答案 1 :(得分:3)

尝试:

SELECT computers.id, 
       group_concat(distinct processors.id) AS p_ids, 
       group_concat(distinct processors.name) AS p_names, 
       group_concat(distinct harddrives.id) AS h_ids, 
       group_concat(distinct harddrives.name) AS h_names
FROM computers
JOIN computer_processors ON (computer_processors.c_id = computers.id) 
JOIN processors ON (processors.id = computer_processors.p_id)
LEFT JOIN computer_harddrives ON (computer_harddrives.c_id = computers.id) 
LEFT JOIN harddrives ON (harddrives.id = computer_harddrives.h_id)
WHERE computers.user_id = 1
group by computers.id

答案 2 :(得分:1)

SELECT computers.id, processors.id AS p_id, processors.name AS p_name, harddrives.id AS h_id, harddrives.name AS h_name
FROM computers

LEFT JOIN computer_processors ON (computer_processors.c_id = computers.id) 
LEFT JOIN processors ON (processors.id = computer_processors.p_id)

LEFT JOIN computer_harddrives ON (computer_harddrives.c_id = computers.id) 
LEFT JOIN harddrives ON (harddrives.id = computer_harddrives.h_id)

WHERE computers.user_id = 1

答案 3 :(得分:0)

select u.ID user_id,
       u.name user_name
       p.id,
       p.name,
       h.id,
       h.name
from USERS u join COMPUTERS c
on u.id=c.USER_ID
join PROCESSORS p
on c.id=p.id
join HARDDRIVES h
on c.id=h.id
where u.id=1