我有一个存储过程,其中包含以下内容(简化示例):
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(我宁愿不这样做),也没有创建临时表的可能性,这对于这种事情来说似乎有点极端
我有什么选择?谢谢。
答案 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 |
+-----+--------+-----+--------+
使用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 |
+-----+--------+------+--------+
这是有效的,因为T2.ID2 = @id
在table2
不为NULL时从@id
返回一行,而当table2
为NULL时,@id
不返回任何行。
使用OPTION(RECOMPILE)
优化工具可以在两种情况下生成最佳计划。你可以看到实际的计划并自己确认,在第二种情况下@id
为NULL时,优化器足够智能,根本不会触及table2
,因为它知道T2.ID2 = NULL
总是假的。