在一次采访中我被问到了这个问题。有2个表A
和B
(它们只有一列id
),其中包含以下数据
Table A
id
--
1
2
3
Table B
id
--
2
3
4
我需要产生以下类型的输出:
id | Present
------------
1 | "In A"
2 | "In A & In B"
3 | "In A & In B"
4 | "In B"
我提供了一个使用Union
子句的解决方案,如下所示:
SELECT id, "In A" FROM A WHERE id NOT IN (SELECT id FROM B)
UNION
SELECT id, "In A & In B" WHERE id IN (SELECT id FROM B)
UNION
SELET id, "In B" WHERE id NOT IN (SELECT id FROM A)
在这种情况下,我使用3个单独的查询,并使用UNION
进行组合。我认为Interview只是在寻找我的方法,而不是确切的查询。就是说,在我提出解决方案之后,他告诉我,至少有一个解决方案仅使用2个查询,并且还存在一个仅使用1个查询的解决方案。我尝试使用FULL OUTER JOIN
,但无法提出具体建议。
那么获得以下输出的更好的查询是什么?采访者没有提到任何特定的数据库,所以我认为存在一个通用的解决方案。但是,如果查询特定于某种SQL风格就可以了。泛型会很好。
答案 0 :(得分:5)
以下是与DBMS完全无关的答案(尽管由于缺乏对FULL OUTER JOIN
的支持而无法在MySQL上使用):
SELECT COALESCE(A.id, B.id) AS id,
CASE WHEN A.id IS NULL THEN 'In B'
WHEN B.id IS NULL THEN 'In A'
ELSE 'In A & In B' END AS Present
FROM A
FULL OUTER JOIN B ON B.id = A.id
输出:
id present
1 In A
2 In A & In B
3 In A & In B
4 In B
该查询依赖于以下事实:如果外部联接的第二个表中没有匹配的行,则将JOIN
编辑具有NULL值的行。因此,如果A.id IS NULL
表示该值仅在表B中。如果B.id IS NULL
则该值仅在表A中。并且如果两个id
的值都不为NULL,则该值必须在两个表中都存在。
答案 1 :(得分:0)
请勿为此使用full outer join
!重复项或NULL
值的行为不佳。我更喜欢union
和聚合:
select id,
(case when in_a = 1 and in_b = 1 then 'In A & In B'
when in_a = 1 then 'In A'
else 'In B'
end) as present
from ((select id, 1 as in_a, 0 as in_b
from a
) union -- on purpose to remove duplicates
(select id, 0, 1
from b
)
) ab
group by id;
在支持concat_ws()
的数据库中,我将其简化为:
select id,
concat_ws(' & ', in_a, in_b) as present
from ((select id, 'In A' as in_a, NULL as in_b
from a
) union -- on purpose to remove duplicates
(select id, NULL, 'In B'
from b
)
) ab
group by id;