2016-07-04 1 views
2

У меня есть хранимая процедура, которая имеет следующий (упрощенный пример):MS SQL - РЕГИСТРИРУЙТЕСЬ только если параметр существует в хранимой процедуре

DECLARE @id int = NULL 
SELECT * FROM table1 t1 
INNER JOIN table2 t2 ON ((@id IS NOT NULL) AND (t2.id = @id)) 

Целью этого является то, чтобы вернуть все строки, если @id не предусмотрено , else возвращает только строки, соответствующие @id.

Работает как ожидалось, если предоставляется @id. Но он не возвращает строк, поэтому @id имеет значение null.

Я подумал, может быть

INNER JOIN table t2 ON (@id IS NULL OR ((@id IS NOT NULL) AND (t2.id = @id))) 

может работать, но если @id равно нулю, то, кажется, вернуть бесконечные ряды (я подождал 30 секунд, и это было в прошлом 1M ряды. (Есть только 150 строки в таблице 1)

Я читал, и большинство других примеров для этого, похоже, используют динамический SQL (чего я бы предпочел не делать) или возможность создания таблицы temp, которая кажется немного экстремальной

Какие у меня варианты? Спасибо.

+0

Вместо этого используйте 'IF @id IS NULL'. Поэтому дайте запрос для случая, что параметр «null» и один для случая с непустым. Это намного эффективнее –

+0

вам следует присоединиться к table1 и table2 как-то –

+0

Попробуйте написать отдельные запросы на основе значения параметра! – Lucky

ответ

1

Я сомневаюсь в вашей таблице присоединиться, попытался упрощена Ваш SQL-запрос

DECLARE @id int = NULL 
SELECT * 
FROM table1 t1 
INNER JOIN table2 t2 ON t1.id=t2.id 
WHERE @id IS NULL OR t2.id = @id 
+0

Полностью согласен, что использование 't1 join t2' имеет смысл только в том случае, если после этого следует' on'-предложение вроде этого, возможно, лучше всего написано как 'INNER JOIN table2 t2 ON t1.id = t2.t1_id', но кроме этого : вот как это должно выглядеть. –

+0

Да для справочного столбца Имя Я не уверен в его имени, поэтому я использовал 't1.id = t2.id' –

+0

Это было отважно, но не решение (до сих пор). Объединив способ, который вы показываете, возвращаемые строки являются конкатенацией t1 и t2, что приводит к множеству записей t1. В случае, когда @id имеет значение null, я хочу только получить 1 каждую строку t1 (как будто соединение никогда не было). – SlowCoder74

0

Оба table1 и table2 имеют один столбец (ID) типа междунар в этом примере. Он должен работать для других типов данных тоже просто нужно изменить, где положение и ISNULL функции в избранном соответственно, как показано ниже (см комментариев для получения дополнительной информации о том, как она работает)

CREATE TABLE [dbo].[TABLE1]([ID] [int] NOT NULL) 
GO 
CREATE TABLE [dbo].[TABLE2]([ID] [int] NOT NULL) 
GO 

---- For INT Datatype ----- 

DECLARE @id int = 1-- NULL -- 
SELECT Distinct A.id_t1 -- , id_t2 -- , A.ID -- , * 
FROM 
(
    SELECT Distinct 
      t1.id as id_t1 , -- Alias the id col differently for clarity 
      t2.id as id_t2 , 
      ISNULL(@id , -1) as ID -- Helper column to help check for NULL value passed for @id. 
    FROM  dbo.table1 t1 
    CROSS JOIN dbo.table2 t2 

) A 
WHERE (A.id_t1 = A.ID AND A.id_t1 = A.id_t2) OR A.ID = -1 -- Use that Helper column A.ID to narrow down the result set to what you want 


---- For Char Datatype ----- 
    DECLARE @id varchar(1) = '1' -- NULL -- Uncomment to Switch between NULL and 

    SELECT Distinct A.id_t1 -- , id_t2 -- , A.ID -- Uncomment as needed for Troubleshooting purposes 
    FROM 
    (
     SELECT Distinct 
       t1.id as id_t1 , 
       t2.id as id_t2 , 
       ISNULL(@id , 'x') as ID -- Helper column to help check for NULL value passed for @id. 
     FROM  dbo.table1 t1 
     CROSS JOIN dbo.table2 t2 

    ) A 
    WHERE (A.id_t1 = A.ID AND A.id_t1 = A.id_t2) OR A.ID = 'x' 
0

У вас есть довольно странный запрос, когда вы имеют декартово произведение двух таблиц.

Это имеет смысл, если ID в table2 уникален. В этом случае запрос ниже всегда будет возвращать все строки из table1 и либо значение одной строки с данными ID от table2, либо NULL в соответствующих столбцах.

Выборочные данные

DECLARE @Table1 TABLE (ID1 int PRIMARY KEY, Value1 int); 
INSERT INTO @Table1(ID1, Value1) VALUES 
(11, 101), 
(12, 102), 
(13, 103), 
(14, 104); 

DECLARE @Table2 TABLE (ID2 int PRIMARY KEY, Value2 int); 
INSERT INTO @Table2(ID2, Value2) VALUES 
(21, 221), 
(22, 222), 
(23, 223); 

запросов с не NULL

DECLARE @id int; 

SET @id = 22; 
SELECT * 
FROM 
    @Table1 AS T1 
    LEFT JOIN @Table2 AS T2 ON T2.ID2 = @id 
OPTION(RECOMPILE); 

+-----+--------+-----+--------+ 
| ID1 | Value1 | ID2 | Value2 | 
+-----+--------+-----+--------+ 
| 11 | 101 | 22 | 222 | 
| 12 | 102 | 22 | 222 | 
| 13 | 103 | 22 | 222 | 
| 14 | 104 | 22 | 222 | 
+-----+--------+-----+--------+ 

not-null

запроса с NULL

SET @id = NULL; 
SELECT * 
FROM 
    @Table1 AS T1 
    LEFT JOIN @Table2 AS T2 ON T2.ID2 = @id 
OPTION(RECOMPILE); 

+-----+--------+------+--------+ 
| ID1 | Value1 | ID2 | Value2 | 
+-----+--------+------+--------+ 
| 11 | 101 | NULL | NULL | 
| 12 | 102 | NULL | NULL | 
| 13 | 103 | NULL | NULL | 
| 14 | 104 | NULL | NULL | 
+-----+--------+------+--------+ 

null

Это работает, потому что T2.ID2 = @id возвращает один ряд с table2 когда @id не NULL и не возвращает ни одной строки из table2 когда @id является NULL.

С OPTION(RECOMPILE) оптимизатор может генерировать оптимальный план в обоих случаях.Вы можете увидеть фактические планы и убедиться в том, что во втором случае, когда @id NULL-оптимизатор достаточно умен, чтобы не дотрагиваться до table2, потому что он знает, что T2.ID2 = NULL всегда неверно.

 Смежные вопросы

  • Нет связанных вопросов^_^