Sql 我需要某种条件连接

Sql 我需要某种条件连接,sql,sql-server,sql-server-2008,left-join,Sql,Sql Server,Sql Server 2008,Left Join,好的,我知道有几篇文章讨论了这一点,但我的问题不能通过连接上的条件where语句(通用解决方案)来解决 我有三个join语句,根据查询参数,我可能需要运行这三个语句的任意组合。我的Join语句非常昂贵,因此我只想在查询需要时执行Join,我不准备编写7组合IF..ELSE..语句来实现这些组合 以下是我迄今为止所用的解决方案,但所有这些都不太理想: LEFT JOIN joinedTable jt ON jt.someCol = someCol WHERE jt.someCol = condit

好的,我知道有几篇文章讨论了这一点,但我的问题不能通过连接上的条件where语句(通用解决方案)来解决

我有三个
join
语句,根据查询参数,我可能需要运行这三个语句的任意组合。我的Join语句非常昂贵,因此我只想在查询需要时执行Join,我不准备编写7组合
IF..ELSE..
语句来实现这些组合

以下是我迄今为止所用的解决方案,但所有这些都不太理想:

LEFT JOIN joinedTable jt
ON jt.someCol = someCol
WHERE jt.someCol = conditions
OR @neededJoin is null
(这太贵了,因为我正在执行连接,即使我不需要它,只是不评估连接)

(这比通常的左键连接更昂贵)

(这一个很理想,它现在是如何编写的,但我正在尝试将其从动态SQL中转换出来)

任何想法或帮助都会很好

编辑: 如果我采用动态SQL方法,我将试图找出构造查询时最有效的方法。考虑到我有三个可选条件,并且我需要所有条件的结果,我当前的查询如下所示:

IF condition one
SELECT from db
INNER JOIN condition one

UNION

IF condition two
SELECT from db
INNER JOIN condition two

UNION

IF condition three
SELECT from db
INNER JOIN condition three
DECLARE @ret TABLE(...) ;

IF <coondition one> BEGIN ;
  INSERT INTO @ret() SELECT ...
END ;

IF <coondition two> BEGIN ;
  INSERT INTO @ret() SELECT ...
END ;

IF <coondition three> BEGIN ;
  INSERT INTO @ret() SELECT ...
END ;

SELECT DISTINCT ... FROM @ret ;
我的非动态查询通过执行左联接来完成此任务:

SELECT from db
LEFT JOIN condition one
LEFT JOIN condition two
LEFT JOIN condition three
WHERE condition one is true
OR condition two is true
OR condition three is true
做什么更有意义?既然“selectfromdb”语句中的所有代码都是相同的?看起来联合条件更有效,但我的查询很长,因为它

谢谢

LEFT JOIN
joinedTable jt ON jt.someCol = someCol AND jt.someCol = conditions AND @neededjoin ...
...

老实说,除非使用文字,否则没有条件联接这样的构造


如果它在SQL语句中,它将被计算。。。因此,不要在SQL语句中使用动态SQL或IF-ELSE,动态SQL解决方案通常是最适合这些情况的,但是如果您真的需要摆脱这一点,则在一个stroed门廊中的一系列IF语句将完成这项工作。这是一个痛苦的过程,您必须编写更多的代码,但这比试图在语句本身中使连接成为条件连接要快。

我会选择这样一种简单而直接的方法:

IF condition one
SELECT from db
INNER JOIN condition one

UNION

IF condition two
SELECT from db
INNER JOIN condition two

UNION

IF condition three
SELECT from db
INNER JOIN condition three
DECLARE @ret TABLE(...) ;

IF <coondition one> BEGIN ;
  INSERT INTO @ret() SELECT ...
END ;

IF <coondition two> BEGIN ;
  INSERT INTO @ret() SELECT ...
END ;

IF <coondition three> BEGIN ;
  INSERT INTO @ret() SELECT ...
END ;

SELECT DISTINCT ... FROM @ret ;
DECLARE@ret表(…);
如果开始;
插入到@ret()中选择。。。
结束;
如果开始;
插入到@ret()中选择。。。
结束;
如果开始;
插入到@ret()中选择。。。
结束;
选择不同的。。。来自@ret;
编辑:我建议使用一个表变量,而不是临时表,这样程序就不会在每次运行时重新编译。一般来说,三个简单的插入有更好的机会获得更好的执行计划,而不是一个大型怪物查询结合所有三个


然而,我们无法猜测估计性能。我们必须以基准来确定它。然而,更简单的代码块在可读性和可维护性方面更好。

动态SQL解决方案在大多数方面都是最好的;您正在尝试使用不同数量的联接运行不同的查询,而无需重新编写查询以执行不同数量的联接—这在性能方面效果不佳


大约在20世纪90年代初,当我做这类事情时,我使用的语言是I4GL,查询是使用其CONSTRUCT语句构建的。这用于生成WHERE子句的一部分,因此(基于用户输入),它生成的筛选条件可能如下所示:

a.column1 BETWEEN 1 AND 50 AND
b.column2 = 'ABCD' AND
c.column3 > 10
在那些日子里,我们没有现代的连接符号;我们走的时候我得临时凑合一下。通常有一个核心表(或一组核心表)始终是查询的一部分;还有一些表可选地作为查询的一部分。在上面的示例中,我假设“c”是主表的别名。代码的工作方式是:

  • 请注意,查询中引用了表“a”:
    • 在FROM子句中添加“FullTableName AS a”
    • 在WHERE子句中添加连接条件“和a.join1=c.join1”
  • 请注意,表“b”已被引用。。。
    • 向FROM子句和WHERE子句添加位
  • 从SELECT列表(通常是固定的)、from子句和WHERE子句中组装SELECT语句(偶尔也使用诸如GROUPBY、HAVING或ORDERBY等修饰)
这里应该应用相同的基本技术,但细节略有不同

首先,您没有要分析的字符串;在其他情况下,您知道需要将哪些表添加到查询中。所以,你仍然需要设计一些东西,以便它们可以组装,但是

  • SELECT子句及其SELECT列表可能已修复。它将标识查询中必须存在的表,因为值是从这些表中提取的
  • FROM子句可能由一系列连接组成

    • 其中一部分是核心查询:

      FROM CoreTable1 AS C1
      JOIN CoreTable2 AS C2
           ON C1.JoinColumn = C2.JoinColumn
      JOIN CoreTable3 AS M
           ON M.PrimaryKey = C1.ForeignKey
      
    • 可根据需要添加其他表格:

      JOIN AuxilliaryTable1 AS A
           ON M.ForeignKey1 = A.PrimaryKey
      
    • 或者,您可以指定完整查询:

      JOIN (SELECT RelevantColumn1, RelevantColumn2
              FROM AuxilliaryTable1
             WHERE Column1 BETWEEN 1 AND 50) AS A
      
    • 在第一种情况下,您必须记住将WHERE条件添加到主WHERE子句中,并信任DBMS优化器将条件移动到JOIN表中,如图所示。一个好的优化器会自动做到这一点;一个贫穷的人可能不会。使用查询计划帮助您确定DBMS的能力

  • 为联接操作中未涉及的任何表间条件以及基于核心表的任何筛选条件添加WHERE子句。注意,我主要是从额外的标准(和操作)而不是替代标准(或操作)的角度来考虑的,但是只要小心地将表达式插入括号中,您就可以处理这些标准或操作

  • 有时,您可能需要添加几个连接条件来将一个表连接到查询的核心,这并不罕见

  • 添加任何GROUP BY、HAVING或ORDER BY子句(或限制,或任何其他装饰)

请注意,您需要一个
JOIN AuxilliaryTable1 AS A
     ON M.ForeignKey1 = A.PrimaryKey
JOIN (SELECT RelevantColumn1, RelevantColumn2
        FROM AuxilliaryTable1
       WHERE Column1 BETWEEN 1 AND 50) AS A
LEFT JOIN joinedTable jt
   ON jt.someCol = someCol
   AND jt.someCol = conditions
   AND @neededJoin = 1 -- or whatever indicates join is needed
Col1  Col2 TableCode
  1     2    A
  1     4    A
  1     3    B
  1     5    B
  2     2    C
  2     5    C
  1     11   C
SELECT
   V.*,
   LookedUpValue =
      CASE M.TableCode
      WHEN 'A' THEN A.Value
      WHEN 'B' THEN B.Value
      WHEN 'C' THEN C.Value
      END
FROM
    ValueMaster V
    INNER JOIN JoinMap M ON V.Col1 = M.oOl1 AND V.Col2 = M.Col2
    LEFT JOIN TableA A ON M.TableCode = 'A'
    LEFT JOIN TableB B ON M.TableCode = 'B'
    LEFT JOIN TableC C ON M.TableCode = 'C'
with m as (select 1 Num, 'One' Txt from dual union select 2, 'Two' from dual union select 3, 'Three' from dual),
t1 as (select 1 Num from dual union select 11 from dual),
t2 as (select 2 Num from dual union select 22 from dual),
t3 as (select 3 Num from dual union select 33 from dual)
SELECT m.*
      ,CASE 1
         WHEN 1 THEN
          t1.Num
         WHEN 2 THEN
          t2.Num
         WHEN 3 THEN
          t3.Num
       END SelectedNum
  FROM m
  LEFT JOIN (SELECT * FROM t1 WHERE 1 = 1) t1 ON m.Num = t1.Num
  LEFT JOIN (SELECT * FROM t2 WHERE 1 = 2) t2 ON m.Num = t2.Num
  LEFT JOIN (SELECT * FROM t3 WHERE 1 = 3) t3 ON m.Num = t3.Num