如何在SQL Server 2012中按照特定条件进行表的INNER JOIN操作?

4
我有一系列连接在我的SELECT语句中,我希望执行。然而,我只想在满足某个条件时执行最后一个连接(INNER JOIN)。 该查询通过将逗号分隔的单词字符串分离为单词表来创建CTE。我还要将这个CTE与另一个表连接以过滤结果。但是,如果用户没有输入任何字符串,我不想连接这个表。是否有办法在INNER JOIN上加入一些条件?
SELECT  dt.Document_ID, 
    dt.Document_NAME, 
    c.Company_ID,
    c.Company_NAME, 
    ct.Category_ID,
    ct.Category_NAME,
    dt.Employee_ID,
    e.First_NAME AS Employee_First_NAME,
    e.Last_NAME AS Employee_Last_NAME,
    p.Project_ID,
    p.Project_NAME,
    dt.Document_DATE,
    dt.Updated_By_ID,
    u.First_NAME AS Updated_First_NAME,
    u.Last_NAME AS Updated_Last_NAME
FROM Documents_T1 AS dt
    LEFT JOIN Companies_T1 AS c ON c.Company_ID=dt.Company_ID
    LEFT JOIN Categories_T1 AS ct ON ct.Category_ID=dt.Category_ID
    LEFT JOIN Users_T1 AS e ON e.User_ID=dt.Employee_ID
    LEFT JOIN Projects_T1 AS p ON p.Project_ID=dt.Project_ID
    LEFT JOIN Users_T1 AS u ON u.User_ID=dt.Updated_By_ID 
    INNER JOIN TagsCTE AS tcte ON tcte.Document_ID=dt.Document_ID
2个回答

1
不,无论代码中是否存在,都将执行 INNER JOIN。但是,您可以使用 LEFT JOIN,并在连接条件中包括任何测试以确定是否应执行连接。这样做的效果是,如果条件为真,则会根据其余的标准执行连接,如果条件为假,则在这些行中获取联接表的 NULL 结果。
SELECT  dt.Document_ID, 
    dt.Document_NAME, 
    c.Company_ID,
    c.Company_NAME, 
    ct.Category_ID,
    ct.Category_NAME,
    dt.Employee_ID,
    e.First_NAME AS Employee_First_NAME,
    e.Last_NAME AS Employee_Last_NAME,
    p.Project_ID,
    p.Project_NAME,
    dt.Document_DATE,
    dt.Updated_By_ID,
    u.First_NAME AS Updated_First_NAME,
    u.Last_NAME AS Updated_Last_NAME
FROM Documents_T1 AS dt
    LEFT JOIN Companies_T1 AS c ON c.Company_ID=dt.Company_ID
    LEFT JOIN Categories_T1 AS ct ON ct.Category_ID=dt.Category_ID
    LEFT JOIN Users_T1 AS e ON e.User_ID=dt.Employee_ID
    LEFT JOIN Projects_T1 AS p ON p.Project_ID=dt.Project_ID
    LEFT JOIN Users_T1 AS u ON u.User_ID=dt.Updated_By_ID 
    **LEFT** JOIN TagsCTE AS tcte ON tcte.Document_ID=dt.Document_ID AND <<condition>>

1

实际上您根本不需要使用连接。您需要将这些信息放在where子句中。

SELECT
    dt.Document_ID, 
    dt.Document_NAME, 
    c.Company_ID,
    c.Company_NAME, 
    ct.Category_ID,
    ct.Category_NAME,
    dt.Employee_ID,
    e.First_NAME AS Employee_First_NAME,
    e.Last_NAME AS Employee_Last_NAME,
    p.Project_ID,
    p.Project_NAME,
    dt.Document_DATE,
    dt.Updated_By_ID,
    u.First_NAME AS Updated_First_NAME,
    u.Last_NAME AS Updated_Last_NAME 
FROM Documents_T1 AS dt
    LEFT JOIN Companies_T1 AS c ON c.Company_ID=dt.Company_ID
    LEFT JOIN Categories_T1 AS ct ON ct.Category_ID=dt.Category_ID
    LEFT JOIN Users_T1 AS e ON e.User_ID=dt.Employee_ID
    LEFT JOIN Projects_T1 AS p ON p.Project_ID=dt.Project_ID
    LEFT JOIN Users_T1 AS u ON u.User_ID=dt.Updated_By_ID  
WHERE
    dt.ID IN (SELECT Document_ID FROM TagsCTE)
    OR
    (SELECT TOP 1 ID FROM TagsCTE) IS NULL

用一个表D和表T来简单解释
SELECT * FROM D
WHERE
 D.ID IN (SELECT ID FROM T)
 OR (SELECT TOP 1 ID FROM T) IS NULL

2
我不喜欢语法(SELECT TOP 1 ID FROM T) IS NULL,因为它会产生歧义。如果T没有行,则确实会成功,但是如果它选择的第一个ID恰好具有空值(在这种情况下可能不太可能,但谁知道呢...),它也会成功。如果您使用此结构,我建议使用(SELECT COUNT(1) FROM T) = 0NOT EXISTS (SELECT NULL FROM T)或更清晰的内容。 - Joe Enos
@JoeEnos,阅读问题后,我不认为TagsCTE表中会有空值。这可能不太美观,但由于您无法在where子句中有条件地包含表格,因此这是最有效的解决方法。您还可以创建一个存储过程,根据TagsCTE中是否有数据调用两个SQL语句中的一个。同样,它看起来可能不太优雅,但它是可行的。 - Jason Geiger

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