Объединение на одной из двух таблиц на основе параметра - PullRequest
1 голос
/ 27 мая 2011

Не уверен, что это можно сделать, но вот что я пытаюсь сделать.

У меня есть две таблицы: Таблица 1 называется Задача и содержит все возможные имена задач Таблица 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 ]

3 голосов
/ 27 мая 2011

Не переусердствуйте.Поместите его в сохраненный процесс следующим образом:

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'

Или просто прямой 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
2 голосов
/ 27 мая 2011

Делать это точно так, как вы делаете это сейчас, - лучший способ.Одно единственное утверждение, которое пытается каким-то образом динамически объединить одно из двух утверждений, - это последнее, что вам нужно.T-SQL - это язык для доступа к данным, а не для программирования повторного использования кода.Если вы пытаетесь создать единый оператор, оптимизатор должен разработать план, который всегда работает, независимо от значения @TaskControl, поэтому план всегда должен будет объединить обе таблицы.

Более длительное обсуждение этой темы: Условия динамического поиска в T-SQL (динамическое объединение относится к той же теме, что и динамический поиск).

1 голос
/ 27 мая 2011

Если они совместимы с UNION, вы можете сделать это. При быстром тестировании этот конец показывает только доступ к соответствующей таблице.

Однако я больше согласен с ответами JNK и Ремуса. Это требует затрат на перекомпиляцию для каждого вызова и не приносит особой выгоды.

;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)
0 голосов
/ 27 мая 2011

Попробуйте следующее. Следует избегать привязки плана хранимой процедуры к значению параметра, переданного во время первого выполнения хранимой процедуры (подробности см. Анализ параметров SQL Server ):

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, но значение 1-го переданного параметра не должно влиять на план выполнения, к которому привязывается. Но если производительность является проблемой, запустите трассировку sql с профилировщиком и посмотрите, используется ли кэшированный план выполнения повторно или инициирована перекомпиляция.

Тем не менее, одна вещь: вам необходимо убедиться, что каждый отдельный select в UNION возвращает точно такие же столбцы. Каждый select в UNION должен иметь одинаковое количество столбцов, и каждый столбец должен иметь общий тип (или преобразование по умолчанию в общий тип). 1-й select определяет количество, типы и имена столбцов в наборе результатов.

0 голосов
/ 27 мая 2011

Я не знаю, насколько хорошая производительность будет, и она не будет хорошо масштабироваться, если вы добавите дополнительные необязательные таблицы, но это должно работать в ситуации, которую вы представляете.

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
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...