基于参数加入两个表中的一个

时间:2011-05-27 18:31:50

标签: sql tsql sql-server-2008 join

不确定是否可以这样做,但这是我想要做的。

我有两张桌子: 表1称为Task,它包含所有可能的任务名称 表2称为Task_subset,它仅包含表1中包含的任务名称的子集

我有一个名为@TaskControl的变量,它作为参数传入,它等于Table1或Table2

基于@TaskControl变量的值,我想加入一个任务表

例如:

If @TaskControl = 'Table1':
Select * From Orders O Join Task T on T.id = O.id

If @TaskControl = 'Table2):
Select * From Orders O Join Task_subset T on T.id = O.id

我该怎么做,Sql Server 08

5 个答案:

答案 0 :(得分:3)

不要过度复杂化。将它放入存储过程中,如下所示:

CREATE PROCEDURE dbo.MyProcedure(@TaskControl varchar(20))
AS

If @TaskControl = 'Table1'
    Select * From Orders O Join Task T on T.id = O.id

ELSE If @TaskControl = 'Table2'
    Select * From Orders O Join Task_subset T on T.id = O.id

ELSE SELECT 'Invalid Parameter'

或者只是没有proc的直接TSQL:

If @TaskControl = 'Table1'
    Select * From Orders O Join Task T on T.id = O.id

ELSE If @TaskControl = 'Table2'
    Select * From Orders O Join Task_subset T on T.id = O.id

答案 1 :(得分:2)

完全像现在这样做是最好的方法。有一个单一的语句试图以某种方式动态地连接两个语句之一是你想要的最后一件事。 T-SQL是一种用于数据访问的语言,而不是用于DRY代码重用编程的语言。如果您尝试使用单个语句,则优化程序必须提供始终的计划,无论@TaskControl的值是什么,因此计划始终必须同时加入表。

关于此主题的更长时间的讨论是Dynamic Search Conditions in T-SQL(您的动态联接属于与动态搜索相同的主题)。

答案 2 :(得分:1)

如果它们UNION兼容,你可以试一试。从快速测试结果来看,它似乎只能访问相关表格。

我更赞同JNK和Remus的答案。这对每次调用都有重新编译成本,并没有多大好处。

;WITH T AS
(
SELECT  'Table1' AS TaskControl, id 
FROM Task
UNION ALL
SELECT  'Table2' AS TaskControl, id 
FROM Task_subset
)
SELECT *
FROM T
 JOIN Orders O on T.id = O.id 
WHERE TaskControl = @TaskControl
OPTION (RECOMPILE)

答案 3 :(得分:0)

我不知道性能会有多好,而且当您添加其他可选表时,这不会很好地扩展,但这应该适用于您提供的情况。

SELECT
    O.some_column,
    COALESCE(T.some_task_column, TS.some_task_subset_column)
FROM
    Orders O
LEFT OUTER JOIN Tasks T ON
    @task_control = 'Tasks' AND
    T.id = O.id
LEFT OUTER JOIN Task_Subsets TS ON
    @task_control = 'Task Subsets' AND
    TS.id = O.id

答案 4 :(得分:0)

尝试以下方法。它应该避免存储过程计划根据在第一次执行存储过程期间传递的参数值进行绑定(有关详细信息,请参阅SQL Server Parameter Sniffing):

create proc dbo.foo

  @TaskControl varchar(32)

as

  declare @selection varchar(32)
  set @selection = @TaskControl

    select *
    from dbo.Orders t
    join dbo.Task   t1 on t1.id = t.id
    where @selection = 'Table1'
  UNION ALL  
    select *
    from dbo.Orders      t
    join dbo.Task_subset t1 on t1.id = t.id
    where @selection = 'Table2'

  return 0
go

也不应该为每次调用重新编译存储过程,因为@Martin建议可能会发生,但传入的参数值1st不应该影响绑定的执行计划。但是,如果性能是一个问题,请使用分析器运行sql跟踪,并查看是否重用了缓存的执行计划或是否触发了重新编译。

但有一件事是:您需要确保select中的每个UNION返回完全相同的列。 select中的每个UNION必须具有相同的列数,并且每列必须具有公共类型(或默认转换为公共类型)。第一个select定义结果集中列的数量,类型和名称。