条件连接语句 SQL Server

81

以下操作是否可行:

IF [a] = 1234 THEN JOIN ON TableA 
ELSE JOIN ON TableB
如果是这样,正确的语法是什么?

如果是这样,正确的语法是什么?


1
我相信您需要使用动态SQL来获得所需的结果。不过,您可以更详细地解释您的问题,也许会有更好的整体解决方案。 - Will
1
请提供更多的样本数据以便详细说明。 - Bhasyakarulu Kottakota
4
简短而正确的答案是“不行”。可以执行类似于select ... join on tableA on .... where [A] = 1234 union all select ... join on tableA on .... where [A] <> 1234 or [A] is null的操作。 - Shannon Severance
1
"[a]"是什么 - 一个变量、表格吗?你在执行SELECT语句吗?FROM子句中的表格是哪个?有外键吗?你可能可以在JOIN子句中放置不同的条件 - 为了实现我认为你想要的功能,但需要更完整的查询(包括SELECT、FROM和外键引用,如果适用)。 - marksiemers
1
@bummi,看起来这个问题与您标记为可能重复的那个不同,因为它是连接2个不同的表,而您链接的那个是使用2个不同的条件集连接到同一个表。 - simo.3792
5个回答

101

我认为你所要求的可以通过使用LEFT JOINInitial表连接到Option_AOption_B两个表,生成类似于以下内容的结果:

Initial LEFT JOIN Option_A LEFT JOIN NULL
OR
Initial LEFT JOIN NULL LEFT JOIN Option_B

示例代码:

SELECT i.*, COALESCE(a.id, b.id) as Option_Id, COALESCE(a.name, b.name) as Option_Name
FROM Initial_Table i
LEFT JOIN Option_A_Table a ON a.initial_id = i.id AND i.special_value = 1234
LEFT JOIN Option_B_Table b ON b.initial_id = i.id AND i.special_value <> 1234

完成这一步后,您需要“忽略”空值集。在SELECT行中,需要注意一个额外的技巧,即需要决定如何处理空字段。如果Option_A和Option_B表相似,则可以使用COALESCE函数返回第一个非空值(如示例所示)。

另一种选择是,您只需列出Option_A字段和Option_B字段,让使用ResultSet的任何内容来处理确定使用哪些字段。


谢谢!这帮助我在我的头脑中找到了正确的前进道路。 :) - Per Lundberg

18

这只是为了补充一点,即查询可以根据条件动态构建。以下是一个示例。

DECLARE @a INT = 1235
DECLARE @sql VARCHAR(MAX) = 'SELECT * FROM [sourceTable] S JOIN ' + IIF(@a = 1234,'[TableA] A ON A.col = S.col','[TableB] B ON B.col = S.col') 

EXEC(@sql)
--Query will be
/*
SELECT * FROM [sourceTable] S JOIN [TableB] B ON B.col = S.col
*/

4
您之前已经回答了这个问题,现在我看到了这个答案的价值...特别是与集成有关的部分...再次感谢! - J.S. Orris

3

你可以使用联合来解决这个问题

select a, b
from tablea
join tableb on tablea.a = tableb.a
where b = 1234
union
select a, b
from tablea
join tablec on tablec.a = tableb.a
where b <> 1234

如果表列具有不同的“排序规则”,会发生什么? - bareMetal
UNION [ALL]如果结果表具有相同的列。 - qwr

2

我不同意建议使用两个左连接的方法。我认为表值函数更合适,这样你就不需要为每个条件进行所有的coalesce和附加连接。

CREATE FUNCTION f_GetData (
    @Logic VARCHAR(50)
) RETURNS @Results TABLE (
    Content VARCHAR(100)
) AS
BEGIN
    IF @Logic = '1234'
        INSERT @Results
            SELECT Content
            FROM Table_1
    ELSE
        INSERT @Results
            SELECT Content
            FROM Table_2
    RETURN
END
GO

SELECT *
FROM InputTable
    CROSS APPLY f_GetData(InputTable.Logic) T

1
我还没有测试过,但是我猜想这种方法在大规模情况下可能不如外连接方法表现好。但如果您有其他看法,我很愿意学习。 - Nick.McDermaid
我认为这取决于您的2个表的大小,以及您是否认为您可能需要在将来在3个或4个或更多个表之间进行决策。如果您认为可能涉及3个以上的表决策,则一定要避免使用外连接,因为这会很快变得混乱。但是,您是正确的,编写的代码返回整个Table_1或Table_2,由于它是TVF,您无法获得统计信息,以便查询优化器在执行计划中利用。为了减轻这种情况,请向函数添加附加参数,仅返回输出中的行(不打算使用where过滤)。 - Jason W
任何“不要使用WHERE过滤器”的意思是避免从外部查询的函数输出中过滤列 - 您希望过滤发生在table_a或table_b的函数内部。 - Jason W
就像 SQL 中的大多数事情一样,有大约十几种方法可以完成每件事。一些方法在你了解所需行为和实现限制后显然效率低下。如果 table_1 和 table_2 具有相同的完整字段列表(在这种情况下,数据库可能没有得到很好的优化),则此解决方案可能会更好地工作。如果它们包含不同的数据,则无法帮助。如果只需要从 JOIN 表中获取一个或两个字段,则这可能是过度设计 - 因为一个或两个 COALESCE 并不难实现。 - simo.3792
完全正确。有做事情的每种方法都有权衡。这两种方法都是完全有效的。 - Jason W

1

我认为更好的方式是以不同的方式思考您的查询,并将其视为集合

我相信,如果您进行两个单独的查询,然后使用UNION将它们连接起来,这样可以提高性能并使代码更易读。


1
这只是一个提示,因此适合作为评论,而不是答案。一个好的答案将包括实际解决方案,而不仅仅是一般性的有用建议。 - Dale K

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接