在子查询中处理null

时间:2013-04-24 12:08:49

标签: mysql sql join null

我和我有两张桌子。假设有一个动作列表(我工作的原始表有一个发送和接收的消息列表),另一个是用户表,其中包含用户的全名。我已经复制了我现在所拥有的问题。

在actions表(消息表)中找到的用户可能不在users表中。我正在使用子查询来针对actions表的原始查询中的用户名选择用户的全名。当actions表中的用户不在users表中时,MySQL返回 NULL ,这是预期的。但相反,我希望它返回原始用户名。

说,praveen在users表和actions表中都有。所以,我得到这样的结论:Praveen Kumar likes something.。说,我有另一个用户名bluff,用户表中没有该用户名,操作就是这样:NULL shares something.。在这里,而不是 NULL ,是否可以返回用户名本身,如bluff shares something.

此处提供了我的SQL Fiddle,架构详细信息和其他参考资料。如果我能以更好的方式做到这一点,请告诉我。感谢。

MySQL 5.5.30架构设置

CREATE TABLE `users`
    (`username` varchar(15), `fullname` varchar(15))
;

INSERT INTO `users`
    (`username`, `fullname`)
VALUES
    ('praveen', 'Praveen Kumar'),
    ('jeff', 'Jeff Atwood')
;

CREATE TABLE `actions`
    (`user` varchar(7), `action` varchar(7))
;

INSERT INTO `actions`
    (`user`, `action`)
VALUES
    ('praveen', 'Like'),
    ('jeff', 'Comment'),
    ('praveen', 'Answer'),
    ('praveen', 'Share'),
    ('jeff', 'Comment'),
    ('bluff', 'Share'),
    ('jeff', 'Like')
;

查询

SELECT *, (
  SELECT `fullname` FROM `users` WHERE `user` = `username`
) AS `name` FROM `actions`

Result

+---------+---------+---------------+
| USER    | ACTION  | NAME          |
+---------+---------+---------------+
| praveen |    Like | Praveen Kumar |
|    jeff | Comment | Jeff Atwood   |
| praveen |  Answer | Praveen Kumar |
| praveen |   Share | Praveen Kumar |
|    jeff | Comment | Jeff Atwood   |
|   bluff |   Share | (null)        |
|    jeff |    Like | Jeff Atwood   |
+---------+---------+---------------+

预期输出

+---------+---------+---------------+
| USER    | ACTION  | NAME          |
+---------+---------+---------------+
| praveen |    Like | Praveen Kumar |
|    jeff | Comment | Jeff Atwood   |
| praveen |  Answer | Praveen Kumar |
| praveen |   Share | Praveen Kumar |
|    jeff | Comment | Jeff Atwood   |
|   bluff |   Share | bluff         |
|    jeff |    Like | Jeff Atwood   |
+---------+---------+---------------+

3 个答案:

答案 0 :(得分:3)

使用IFNULL

SELECT *, IFNULL((
  SELECT `fullname` FROM `users` WHERE `user` = `username`
),`user`) AS `name` FROM `actions`

SQLFiddle

修改

同样COALESCE执行相同的操作

SELECT *, COALESCE((
  SELECT `fullname` FROM `users` WHERE `user` = `username`
),`user`) AS `name` FROM `actions`

答案 1 :(得分:3)

您可以LEFT JOIN使用CASE语句,如下所示:

SELECT User, Action 
       ,CASE WHEN Fullname IS NULL 
             THEN User 
             ELSE Fullname 
              END as Name
FROM actions a
LEFT JOIN users u
ON a.User = u.username;

输出

|    USER |  ACTION |          NAME |
-------------------------------------
| praveen |    Like | Praveen Kumar |
|    jeff | Comment |   Jeff Atwood |
| praveen |  Answer | Praveen Kumar |
| praveen |   Share | Praveen Kumar |
|    jeff | Comment |   Jeff Atwood |
|   bluff |   Share |         bluff |
|    jeff |    Like |   Jeff Atwood |

See this SQLFiddle

答案 2 :(得分:0)

由于得到了公认的答案,我在生产代码中使用了它,并且性能令人赞叹。注意mysql 1的用法(类似于sql server的SELECT TOP 1)。并注意COALESCE和CONCAT的组合用法,即,如果郊区为null,则不附加多余的逗号,因为','+ null = null,然后使用合并将成为空字符串。

SELECT 
    COALESCE((SELECT Customer.Name From Customer WHERE Quote.CustomerId = Customer.Id LIMIT 1), '') As CustomerName, 
    Description, 
    (CONCAT(COALESCE(DeliveryStreet, ''), COALESCE(CONCAT(', ', DeliverySuburb), ''), COALESCE(CONCAT(', ', DeliveryCity), ''), COALESCE(CONCAT(', ', DeliveryPostcode), ''))) as DeliveryAddress, 
    COALESCE(DATE_FORMAT(CreatedDate, '%d %b %y'), '') as QuoteCreatedDate, 
    COALESCE((SELECT User.Name FROM QuoteStatusHistory INNER JOIN Status ON Status.Id = QuoteStatusHistory.StatusId INNER JOIN User ON QuoteStatusHistory.UserId = User.Id WHERE QuoteStatusHistory.QuoteId = Quote.Id AND QuoteStatusHistory.StatusId = 1 ORDER BY QuoteStatusHistory.CreatedDate DESC LIMIT 1), '') as CreatedBy, 
    COALESCE((SELECT DATE_FORMAT(QuoteStatusHistory.CreatedDate, '%d %b %y') FROM QuoteStatusHistory WHERE QuoteStatusHistory.QuoteId = Quote.Id AND QuoteStatusHistory.StatusId = 2 ORDER BY QuoteStatusHistory.CreatedDate DESC LIMIT 1), '') as OrderDate, 
    COALESCE((SELECT User.Name FROM QuoteStatusHistory INNER JOIN Status ON Status.Id = QuoteStatusHistory.StatusId INNER JOIN User ON QuoteStatusHistory.UserId = User.Id WHERE QuoteStatusHistory.QuoteId = Quote.Id AND QuoteStatusHistory.StatusId = 2 ORDER BY QuoteStatusHistory.CreatedDate DESC LIMIT 1), '') as OrderedBy, 
    COALESCE((SELECT DATE_FORMAT(QuoteStatusHistory.CreatedDate, '%d %b %y') FROM QuoteStatusHistory WHERE QuoteStatusHistory.QuoteId = Quote.Id AND QuoteStatusHistory.StatusId IN (3, 4) ORDER BY QuoteStatusHistory.CreatedDate DESC LIMIT 1), '') as DispatchDate, 
    QuotePrice,
    COALESCE((SELECT Status.Name FROM QuoteStatusHistory INNER JOIN Status ON Status.Id = QuoteStatusHistory.StatusId WHERE QuoteStatusHistory.QuoteId = Quote.Id ORDER BY QuoteStatusHistory.CreatedDate DESC LIMIT 1), '') as QuoteStatus 
FROM Quote