我有以下查询:
DECLARE @Cond_ition int = 2
SELECT T.Id, T.Description, T.A_Id, T.B_Id, T.C_Id FROM Table1 as T
JOIN TableA as A ON A.Id = T.A_Id AND A.GroupId = @Cond_ition
JOIN TableB as B ON B.Id = T.B_Id AND B.GroupId = @Cond_ition
JOIN TableC as C ON C.Id = T.C_Id AND C.GroupId = @Cond_ition
列A_Id,B_Id和C_Id在T的各行中具有少量的不同值。 变量@Cond_ition实际上是该查询需要在其中运行的存储过程的参数。
查询将仅从T中返回在A,B和C中具有匹配项的行,除非这些表中的一个或多个表不具有匹配项,否则这很好。 如果例如B为空或与A不匹配,则查询应返回T中与A和C匹配的行。如果B和C为空,则我需要T中与A匹配的行。全部为空或没有匹配项,那么我需要来自T的所有行。 因此,如果有匹配项,则应充当INNER JOIN,但如果没有匹配项,则应充当LEFT JOIN。
关于如何从联接中获得这种双重“效果”的任何想法?
*编辑:根据要求,我添加了示例数据
Table T
Id Description A_Id B_Id C_Id
-- ----------- ---- ---- ----
1 desc1 FANTA CAN LIGHT
2 something2 SPRITE BOTTLE LIGHT
3 more3 SPRITE CAN ZERO
4 name4 7UP BOTTLE ZERO
5 label5 GLASS REGULAR
**Case 1**
Table A
Id GroupId
-- -------
FANTA 2
SPRITE 2
Table B
Id GroupId
-- -------
CAN 5
*Expected result*
rows 1, 2 and 3
**Case 2**
Table A
Id GroupId
-- -------
FANTA 2
SPRITE 2
Table B
Id GroupId
-- -------
CAN 2
CAN 5
*Expected result*
rows 1 and 3
**Case 3**
Id GroupId
-- -------
FANTA 2
SPRITE 2
Table B
Id GroupId
-- -------
CAN 2
CAN 5
Table C
Id GroupId
-- -------
ZERO 2
*Expected result*
row 3
**Case 4**
Tables A, B and C empty or no rows with GroupId = 2
*Expected result*
all rows of T
答案 0 :(得分:4)
如果我的理解正确,那么您只希望包含匹配项的行(如果有)。如果根本没有匹配的行,那么您需要table1
中的所有行。
您可以使用UNION ALL
处理此问题:
WITH tabc as (
SELECT T.Id, T.Description, T.A_Id, T.B_Id, T.C_Id
FROM Table1 T LEFT JOIN
TableA A
ON A.Id = T.A_Id AND A.GroupId = @Cond_ition LEFT JOIN
TableB B
ON B.Id = T.B_Id AND B.GroupId = @Cond_ition LEFT JOIN
TableC C
ON C.Id = T.C_Id AND C.GroupId = @Cond_ition
WHERE T.A_Id IS NOT NULL OR T.B_Id IS NOT NULL OR T.C_Id IS NOT NULL
)
SELECT tabc.*
FROM tabc
UNION ALL
SELECT t.*, NULL, NULL, NULL
FROM table1 t
WHERE NOT EXISTS (SELECT 1 FROM tabc);
答案 1 :(得分:0)
感谢@gordonlinoff的投入,它帮助我找到了解决方案。 这是符合我要求的查询:
SELECT T.Id, T.Description, T.A_Id, T.B_Id, T.C_Id
FROM Table1 T
JOIN (SELECT Id FROM TableA WHERE GroupId = @Cond_ition
UNION
SELECT TOP(1) '' WHERE NOT EXISTS (SELECT TOP(1) Id FROM TableA WHERE GroupId = @Cond_ition)
)
AS A ON ISNULL(T.A_Id,'') = CASE
WHEN NOT EXISTS (SELECT TOP(1) Id FROM TableA WHERE GroupId = @Cond_ition) THEN ISNULL(T.A_Id,'')
ELSE A.Id
END
JOIN (SELECT Id FROM TableB WHERE GroupId = @Cond_ition
UNION
SELECT TOP(1) '' WHERE NOT EXISTS (SELECT TOP(1) Id FROM TableB WHERE GroupId = @Cond_ition)
)
AS B ON ISNULL(T.B_Id,'') = CASE
WHEN NOT EXISTS (SELECT TOP(1) Id FROM TableB WHERE GroupId = @Cond_ition) THEN ISNULL(T.B_Id,'')
ELSE B.Id
END
JOIN (SELECT Id FROM TableC WHERE GroupId = @Cond_ition
UNION
SELECT TOP(1) '' WHERE NOT EXISTS (SELECT TOP(1) Id FROM TableC WHERE GroupId = @Cond_ition)
)
AS C ON ISNULL(T.C_Id,'') = CASE
WHEN NOT EXISTS (SELECT TOP(1) Id FROM TableC WHERE GroupId = @Cond_ition) THEN ISNULL(T.C_Id,'')
ELSE C.Id
END
我在表A,表B和表C的联接中使用UNION。
首先选择获取与条件匹配的行,然后在没有匹配记录的情况下与常量合并。使用常量可确保UNION的结果永远不会为空。
在JOIN的ON子句中,我用CASE再次检查是否没有匹配的记录,在这种情况下,我将加入T本身的字段(使用ISNULL将返回所有行),否则我将加入子表。
我用想要查询的人更新了dbfiddle的查询。