我有以下表格:
用户
生
付款
我有以下问题:
SELECT users.username, users.first_name, users.email,
COUNT(payments.id) as pending_payments
FROM users
LEFT JOIN students ON users.id = students.user_id
LEFT JOIN payments ON payments.student_id = students.id AND payments.is_paid = 0
WHERE users.username LIKE 'testuser';
当用户名存在且没有待付款时,它会返回:
| username | first_name | email | pending_payments |
| testuser | test | testuser@example.com | 0 |
当用户名存在并且有2个待处理付款时,它会返回:
| username | first_name | email | pending_payments |
| testuser2| test2 | testuser@2example.com | 2 |
但是当用户名不存在时,它会返回:
| username | first_name | email | pending_payments |
| NULL | NULL | NULL | 0 |
相反,当用户名不存在时,我想要结果:
空集。
如何修改查询以获得预期结果? (保留用户存在时的行为,但当不存在时返回Empty set,而不是一行将NULL值)。
请参阅SQLfiddle:http://sqlfiddle.com/#!9/aab424/11
修改 提供了工作解决方案: http://sqlfiddle.com/#!9/aab424/72
答案 0 :(得分:3)
如果没有使用GROUP BY子句,像COUNT(*)
这样的聚合函数总是生成一行。因此,如果您想要一个空结果,请使用GROUP BY子句:
SELECT users.username, users.first_name, users.email,
COUNT(payments.id) as pending_payments
FROM users
LEFT JOIN students ON users.id = students.user_id
LEFT JOIN payments ON payments.student_id = students.id AND payments.is_paid = 0
WHERE users.username LIKE 'testuser3'
GROUP BY users.username, users.first_name, users.email;
请注意,每个用户使用该用户名将获得一行。如果username
不是唯一的并且您希望为具有相同username
的所有用户获取一行,则可以使用HAVING子句而不是GROUP BY来“删除”“空”行。
SELECT users.username, COUNT(payments.id) as pending_payments
FROM users
LEFT JOIN students ON users.id = students.user_id
LEFT JOIN payments ON payments.student_id = students.id AND payments.is_paid = 0
WHERE users.username LIKE 'testuser3'
HAVING username IS NOT NULL;
这与LEFT或任何JOIN无关。这是聚合函数的工作方式(在MySQL中),你会看到相同的行为,只有一个没有连接的简单例子,如
SELECT username, COUNT(*)
FROM users
WHERE username = 'testuser3';
| username | COUNT(*) |
|----------|----------|
| (null) | 0 |
请注意,此查询不符合SQL标准,并且在严格模式下,您将收到错误,因为选择了username
而未在GROUP BY子句中列出。 (SQLFiddle)。
如果您要为
COUNT()
值之外的列命名,请选择a 应该存在GROUP BY
子句来命名那些相同的列。 否则,会发生以下情况:
如果启用了
ONLY_FULL_GROUP_BY
SQL模式,则会发生错误: [...]如果未启用
ONLY_FULL_GROUP_BY
,则处理查询 将所有行视为一个组,但为每个组选择的值 命名列是不确定的。服务器可以自由选择值 从任何一行: [...]
再次:“服务器可以自由选择任何行的值”。但由于没有匹配的行,因此返回NULL
。
答案 1 :(得分:1)
我认为为用户名等找到的NULL值主要是因为您的查询中缺少分组。
我认为应该可以使用:
SELECT users.username,
users.first_name,
users.email,
SUM(COALESCE( p.is_paid = 0, 0)) as pending_payments
FROM users
LEFT JOIN students s on s.user_id = users.id
LEFT JOIN payments p on p.student_id = s.id
WHERE users.username LIKE 'testuser3'
GROUP BY users.username,
users.first_name,
users.email;
当省略WHERE行时,它将列出所有用户:
SELECT users.username,
users.first_name,
users.email,
SUM(COALESCE( p.is_paid = 0, 0)) as pending_payments
FROM users
LEFT JOIN students s on s.user_id = users.id
LEFT JOIN payments p on p.student_id = s.id
GROUP BY users.username,
users.first_name,
users.email;
它会提及所有用户,即使那些没有任何付款(未决或未付款)的用户或未列入学生表的用户
答案 2 :(得分:0)
你显然在users
表中有用户名为NULL的用户。您可以过滤掉WHERE
子句中的NULL值。
SELECT users.username, users.first_name, users.email,
COUNT(payments.is_paid = 0) as pending_payments
FROM users
LEFT JOIN students ON users.id = students.user_id
LEFT JOIN payments ON payments.student_id = students.id
WHERE users.username LIKE 'testuser' AND users.username IS NOT NULL;
答案 3 :(得分:0)
你收到" null"响应是由LEFT JOIN
语句引起的。即使参数在该表中不匹配,左连接也会完成,因为它们可能构成另一个(连接)表中的列。要仅显示符合条件的结果,请使用INNER JOIN
语句。
此外,您希望COUNT(*)
按用户名付款,您应该GROUP BY
用户名。
尝试以下方法(未经测试,抱歉,不要在电脑前面加上编辑器)
SELECT u.username, u.first_name, u.email, COUNT(p.is_paid) as pending_payments
FROM users u
INNER JOIN students s ON u.id = s.user_id
INNER JOIN payments p ON s.user_id = p.student_id
WHERE u.username LIKE '%testuser%'
AND u.username IS NOT NULL
GROUP BY u.username
ORDER BY p.is_paid DESC, u.username ASC
此外,如果您只想显示已暂停付款的结果,则可以在 使用以下设置进行测试: 下面显示查询结果。第二个查询没有HAVING
之后添加GROUP BY
语句,例如< / p>
HAVING u.pending_payments > 0
HAVING
语句。
答案 4 :(得分:0)
为什么不能使用IS NOT NULL?
SELECT users.username, users.first_name, users.email,
COUNT(payments.id) as pending_payments
FROM users
LEFT JOIN students ON users.id = students.user_id
LEFT JOIN payments ON payments.student_id = students.id AND payments.is_paid = 0
WHERE users.username LIKE 'testuser' and users.username is NOT NULL;