我有一个用户表和一个表,该表跟踪线程以及每个线程中涉及的用户。我试图制作一个SELECT
语句,使我可以查看任何线程,并获取完整的用户列表以及其中是否包含用户的列。最初且天真地,我使用以下内容开始:
SELECT
listusers.idx as Value,
CONCAT(FirstName, ' ', LastName) as Label,
False as selected
FROM
listUsers
WHERE
listusers.customerId = 0
这使我回到了所有用户手中,这时我以编程方式查看了另一个表并手动打开了该表中的用户。
我通过查询尝试执行以下操作-
SELECT l.idx as Value,
CONCAT(FirstName, ' ', LastName) as Label,
IF(h.userId IS NULL,False, True) as Selected
FROM listusers l
LEFT JOIN helpmessageparticipants h ON l.idx = h.userId
WHERE l.customerId = 0 AND
h.parentThreadId={Root Container.threadId})
但是由于某些原因,只会返回被选择的用户。如果只有3个用户在线程中,那么我只能找回这3个用户,并且所有用户都是所选的True
。我想要的最终结果是始终取回所有用户(l.customerId = 0的用户)以及关于某个线程的helpmessageparticipant中是否存在它们的真值列或假布尔值列的附加列。我的第二个查询出了什么问题?
我正在使用MySQL 5.6。
答案 0 :(得分:2)
您需要移动
h.parentThreadId={Root Container.threadId})
条件从WHERE
子句进入联接条件,否则将您的LEFT JOIN
转换为INNER JOIN
。
SELECT l.idx as Value,
CONCAT(FirstName, ' ', LastName) as Label,
IF(h.userId IS NULL,False, True) as Selected
FROM listusers l
LEFT JOIN helpmessageparticipants h ON l.idx = h.userId AND
h.parentThreadId={Root Container.threadId})
WHERE l.customerId = 0
这在'Outer Join Optimization'下的手册中进行了讨论:
对于LEFT JOIN,如果对于所生成的NULL行,WHERE条件始终为false,则将LEFT JOIN更改为内部联接
在您的示例中,对于生成的NULL行,h.parentThreadId={Root Container.threadId})
将为false,因此查询将更改为INNER JOIN
,而您只会取回所选的用户。
答案 1 :(得分:0)
如Nick所指出的,LEFT JOIN
版本要求该条件位于ON
子句中,而不是WHERE
子句中。我将其写为:
SELECT l.idx as Value,
CONCAT(FirstName, ' ', LastName) as Label,
(h.userId IS NOT NULL) as Selected
FROM listusers l LEFT JOIN
helpmessageparticipants h
ON l.idx = h.userId AND
h.parentThreadId = {Root Container.threadId})
WHERE l.customerId = 0;
但是,这假设h
中只有一个匹配项-否则您将获得重复的行。对于单个线程,这可能不是问题。但是您可能还有其他允许多个匹配项的过滤条件。因此,我认为exists
子句可能更合适。
SELECT l.idx as Value,
CONCAT(FirstName, ' ', LastName) as Label,
(EXISTS (SELECT 1
FROM helpmessageparticipants h
WHERE l.idx = h.userId AND
h.parentThreadId = {Root Container.threadId}
)
) as Selected
FROM listusers l LEFT JOIN
WHERE l.customerId = 0;