在 WHERE-Clause for INSERT 中重用子查询结果
Posted
技术标签:
【中文标题】在 WHERE-Clause for INSERT 中重用子查询结果【英文标题】:Reuse subquery result in WHERE-Clause for INSERT 【发布时间】:2012-08-05 16:30:20 【问题描述】:我正在使用 Microsoft SQL Server 2008 我想保存子查询的结果以在以下子查询中重用它。 这可能吗? 这样做的最佳做法是什么? (我对 SQL 很陌生)
我的查询如下:
INSERT INTO [dbo].[TestTable]
(
[a]
,[b]
)
SELECT
(
SELECT TOP 1 MAT_WS_ID
FROM #TempTableX AS X_ALIAS
WHERE OUTERBASETABLE.LT_ALL_MATERIAL = X_ALIAS.MAT_RM_NAME
)
,(
SELECT TOP 1 MAT_WS_NAME
FROM #TempTableY AS Y_ALIAS
WHERE Y_ALIAS.MAT_WS_ID = MAT_WS_ID
--(
--SELECT TOP 1 MAT_WS_ID
--FROM #TempTableX AS X_ALIAS
--WHERE OUTERBASETABLE.LT_ALL_MATERIAL = X_ALIAS.MAT_RM_NAME
--)
)
FROM [dbo].[LASERTECHNO] AS OUTERBASETABLE
我的问题是:
我所做的是否正确。 我用 [a] (=MAT_WS_ID) 的第一个 SELECT 语句的结果替换了 [b] 的 WHERE 子句中的第二个 SELECT 语句(已被注释掉并且与 [a] 完全相同)。 它似乎给出了正确的结果。 但我不明白为什么!
我的意思是 MAT_WS_ID 是临时表 X_ALIAS 和 Y_ALIAS 的一部分。 所以在 [b] 的 SELECT 语句中,在 [b]-select-query 的范围内,MAT_WS_ID 只能从 Y_ALIAS 表中获知。 (或者我错了,我更多的是 C++,可能 SQL 和 C++ 中的作用域完全不同)
我只是想知道在 SQL Server 中重用标量选择结果的最佳方式是什么。 还是我应该不关心并复制每一列的选择,然后 sql 服务器自己优化它?
【问题讨论】:
您应该始终加入表并删除内部选择以获得更好的性能 【参考方案1】:一种方法是outer apply
:
SELECT mat.MAT_WS_ID
, (
SELECT TOP 1 MAT_WS_NAME
FROM #TempTableY AS Y_ALIAS
WHERE Y_ALIAS.MAT_WS_ID = mat.MAT_WS_ID
)
FROM [dbo].[LASERTECHNO] AS OUTERBASETABLE
OUTER APPLY
(
SELECT TOP 1 MAT_WS_ID
FROM #TempTableX AS X_ALIAS
WHERE OUTERBASETABLE.LT_ALL_MATERIAL = X_ALIAS.MAT_RM_NAME
) as mat
【讨论】:
如果有不止一个类似的陈述? 这取决于相似性。一个选项是多个outer apply
,但还有其他选项,例如with
【参考方案2】:
您可以对#TempTableX
和#TempTableY
中的行进行排名,将它们划分为前者中的MAT_RM_NAME
和后者中的MAT_WS_ID
,然后在两个表中使用带有rownum = 1
过滤的普通连接(rownum
是包含两个表中每一个中的排名数字的列):
WITH x_ranked AS (
SELECT
*,
rownum = ROW_NUMBER() OVER (PARTITION BY MAT_RM_NAME ORDER BY (SELECT 1))
FROM #TempTableX
),
y_ranked AS (
SELECT
*,
rownum = ROW_NUMBER() OVER (PARTITION BY MAT_WS_ID ORDER BY (SELECT 1))
FROM #TempTableY
)
INSERT INTO dbo.TestTable (a, b)
SELECT
x.MAT_WS_ID,
y.MAT_WS_NAME
FROM dbo.LASERTECHNO t
LEFT JOIN x_ranked x ON t.LT_ALL_MATERIAL = x.MAT_RM_NAME AND x.rownum = 1
LEFT JOIN y_ranked y ON x.MAT_WS_ID = y.MAT_WS_ID AND y.rownum = 1
;
ORDER BY (SELECT 1)
位是指定不确定排序的技巧,因此会导致查询选择不确定的rownum = 1
行。那就是在没有明确顺序的情况下或多或少地复制您的TOP 1
,但我建议您指定更明智的ORDER BY
子句以使结果更可预测。
【讨论】:
以上是关于在 WHERE-Clause for INSERT 中重用子查询结果的主要内容,如果未能解决你的问题,请参考以下文章
UPDATE IGNORE with function LOWER() in WHERE-clause 啥都不做
select for update 并发insert死锁问题
Triggers:代替/For Insert,哪个会先触发?
Eclipse 中的 insert spaces for tabs 设置方法