在 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 设置方法

insert datetime pugin for sublime text2/3

vector--insert用法