MS SQL - 仅当存储过程中存在参数时才加入

时间:2016-07-04 13:27:54

标签: sql sql-server join stored-procedures param

我有一个存储过程,其中包含以下内容(简化示例):

SELECT "Fut_ID"
FROM (
SELECT *
  FROM "Ce_Data" AS M
  JOIN (SELECT "Fut_ID" AS "Fut_ID2", MAX("Date") AS "Most_Recent"
          FROM "Ce_Data"
         GROUP BY "Fut_ID"
       ) AS R
    ON R."Fut_ID2" = M."Fut_ID" AND R."Most_Recent" = M."Date"
) AS TX

这样做的目的是在没有提供@id的情况下返回所有行,否则只返回与@id匹配的行。

只要提供@id,就可以按预期工作。但它没有返回任何行,@ id为null。

我想,也许

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

可能有效,但是如果@id为null,那么它似乎返回无休止的行(我等了30秒,它已超过1M行。(table1中只有150行)

我已经阅读过,大多数其他实现这一目的的例子似乎都使用了动态SQL(我宁愿不这样做),也没有创建临时表的可能性,这对于这种事情来说似乎有点极端

我有什么选择?谢谢。

3 个答案:

答案 0 :(得分: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

答案 1 :(得分:0)

在此示例中,table1和table2都有一个int类型的列(id)。它应该适用于其他数据类型,只需要相应地更改select中的where子句和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'

答案 2 :(得分: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);

查询非空

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 = @idtable2不为NULL时从@id返回一行,而当table2为NULL时,@id不返回任何行。

使用OPTION(RECOMPILE)优化工具可以在两种情况下生成最佳计划。你可以看到实际的计划并自己确认,在第二种情况下@id为NULL时,优化器足够智能,根本不会触及table2,因为它知道T2.ID2 = NULL总是假的。