【问题标题】:Conditional Joins in Sql Server based on variableSql Server中基于变量的条件连接
【发布时间】:2014-12-01 14:13:55
【问题描述】:

当且仅当某些条件为真时,我才想加入。 前-

Table Employee
emp_no
emp_name
dept_no

Table Departnemt
dept_no
dept_name

declare @takeJoin BIT

select * from Employee e
if @takeJoin then
inner join Department d on e.dept_no=d.dept_no

如果@takeJoin 为 1,则只应采用内部联接,否则应按原样返回来自 Employee 的所有记录。

我们可以通过编写通用 if else 语句来做到这一点吗? 这只是一个示例,实际查询量很大,很笼统

If @takeJoin =1
begin
end
else
begin

end

不会是合适的解决方案。

这样的事情可能吗?

【问题讨论】:

标签: sql sql-server sql-server-2008


【解决方案1】:

使用左联接始终获取员工记录并在 WHERE 子句中将其过滤掉。当@TakeJoin = 0 时,我们在 SELECT 中使用 DISTINCT 来防止 Employee 和 Department 之间潜在的一对多关系(即使这可能是一对零/一)。只是想展示更复杂的一对多场景的技术。

SELECT DISTINCT e.emp_no,
   e.emp_name,
   e.dept_no,
   CASE WHEN @TakeJoin = 1 THEN d.dept_no ELSE NULL END AS dept_dept_no
   CASE WHEN @TakeJoin = 1 THEN d.dept_name ELSE NULL END AS dept_name
FROM Employee e
   LEFT OUTER JOIN Department d ON e.dept_no = d.dept_no
--If @TakeJoin = 1/True, then make sure d.dept_no is not null to filter out Employee
--who have no department.
WHERE
--Mimic INNER JOIN on @TakeJoin = 1
((@TakeJoin = 1 AND d.dept_no IS NOT NULL) OR
--"Ignore" the Join and take all records
@TakeJoin = 0)

【讨论】:

    【解决方案2】:

    最简单的方法是使用if

    if @TakeJOin = 'Yes'
        select *
        from Employee e inner join
             Department d
             on e.dept_no = d.dept_no;
    else
        select *
        from Employee e;
    end;
    

    使用 SQL 中的条件逻辑,这应该可以工作:

    你可以这样做:

    select e.*
    from Employee e left join
         Department d
         on e.dept_no = d.dept_no and @TakeJoin = 'Yes'
    where (@TakeJoin = 'Yes' and d.dept_no is not null) or
          (@TakeJoin <> 'Yes')
    

    请注意,您无法更改返回的列数。如果你这样做:

    select *
    from Employee e left join
         Department d
         on e.dept_no = d.dept_no and @TakeJoin = 'Yes'
    where (@TakeJoin = 'Yes' and d.dept_no is not null) or
          (@TakeJoin <> 'Yes')
    

    然后您将获得Department 的所有列,但当@TakeJoin 为假时,它们将具有NULL 值(无论您如何表示)。

    【讨论】:

    • 如果@TakeJoin = 'No',我认为您会在 Employee 和 Department 之间得到笛卡尔积,因为这适用于两个表中的每一行。
    • @Patrick 。 . .你说的很对。我想我的大脑睡着了。
    【解决方案3】:

    是的, 你可以,但你应该使用选项重新编译:

    声明@doJoin BIT= 0

    SELECT *
    FROM A
    LEFT JOIN B on A.x = B.y and @doJoin = 1
     option (recompile)
    

    如果不重新编译选项,SQL Server 将创建(并缓存)一个更通用的执行计划,该计划始终包括左连接,即使在您的特定情况下不需要它。使用此选项,您将在执行计划中看到对表 A 的聚集索引扫描,而对“B”没有任何访问权限。

    【讨论】:

      猜你喜欢
      • 2022-10-15
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-08-23
      • 2011-04-25
      • 1970-01-01
      • 2018-08-22
      • 2012-09-17
      相关资源
      最近更新 更多