簡體   English   中英

使用SUBQUERY上的INNER JOIN更新不能按預期工作

[英]UPDATE using INNER JOIN on SUBQUERY not working as expected

我試圖在tableA中使用此查詢(原型)從tableD獲取數據來更新col1:

UPDATE tableA
SET TableA.col1 = tableB.col1
FROM tableA 
INNER JOIN
    (SELECT tableC.col1, id 
     FROM
         (SELECT 
              ROW_NUMBER() OVER(PARTITION BY tableD.col1 ORDER BY (tableD.someCol desc) AS "Row Number", 
              col1, id 
          FROM tableD) tableC
     WHERE [Row Number] = 1) tableB ON tableA.id = tableB.id
WHERE 
    some_clause_on_tableA_and_tableB;

但不幸的是,這不能正常工作(不正確的更新),但是如果我將tableB的數據顯式存儲在#temp表中,然后嘗試從該#temp表更新tableA,那么它工作正常(原型查詢):

SELECT * 
INTO #temp 
FROM
    (SELECT 
         ROW_NUMBER() OVER(PARTITION BY tableD.col1 ORDER BY (tableD.someCol desc) AS "Row Number", 
         col1, id 
     FROM tableD) tableC
WHERE
    [Row Number]=1;

UPDATE tableA
SET TableA.col1 = tableB.col1
FROM tableA 
INNER JOIN #temp tableB ON tableA.id = tableB.id
WHERE some_clause_on_tableA_and_tableB;

我不確定為什么后來的工作,但首先不是。 似乎在第一個查詢中,兩個嵌套的子查詢(具有行排名)無法獲取正確的數據,但我可能錯了。 任何幫助將不勝感激!!!

謝謝,薩欽

我感覺你可能錯過了OVER子句利用分區和按關鍵字排序來分組tableD中引用的tableA id。 所以基本上我認為你要做的就是更新tableA中的每個條目,其中tableA的id為每個tableA的id中的第一行。

也許嘗試像tableC子查詢這樣的東西

SELECT
    ROW_NUMBER() OVER (PARTITION BY tableD.fk_to_tableA order by tableD.something
    ,col1 FROM tableD

編輯以下評論

對於它的價值,這是一個你正在嘗試的查詢的簡單例子,它工作正常。 這個例子以什么方式與你的問題不同?

declare @entity table (id int, latestEventId int)

declare @event table (id int, entityId int)

insert into @entity values (1, null), (2, null), (3, null), (4, null), (5, null)

insert into @event values (1, 1), (2, 2), (3, 3), (4, 4), (5, 5), (6, 1), (7, 2), (8, 3), (9, 4), (10, 5), (11, 1), (12, 2), (13, 3), (14, 4), (15, 5)

update tableA
    set tableA.latestEventId = tableB.id
from 
    @entity tableA
inner join
(
    select
        * 
    from 
    (
        select 
            *,
            rn = ROW_NUMBER() over (partition by e.entityId order by e.id desc)
        from
            @event e
    ) tableC
    where
        rn = 1
) tableB 
on tableB.entityId = tableA.id

-- expect the result of entity id's 1 to 5 with the values 11 to 15
select * from @entity

必須有一些事實未涵蓋的內容。 我的意思是,所提出的兩種方法是相同的。 但是,如果您的真實查詢看起來更復雜,那么可能會以某種方式阻止您查看真正的問題。

為了幫助您自己更快地發現問題,您可以通過刪除一級嵌套來簡化查詢: [Row Number]=1條件可以移動到主查詢,如下所示:

UPDATE tableA
    SET TableA.col1 = tableB.col1
FROM tableA INNER JOIN (
    SELECT
        ROW_NUMBER() OVER(PARTITION BY tableD.col1 ORDER BY (tableD.someCol desc) AS "Row Number",
        col1,
        id
    FROM tableD
) tableB
ON tableA.id = tableB.id
WHERE some_clause_on_tableA_and_tableB
  AND tableB.[Row Number] = 1;

此外,由於您並未真正為tableA分配新別名,因此可以從UPDATE語句的FROM子句中省略它,如下所示:

UPDATE tableA
    SET TableA.col1 = tableB.col1
FROM (
    SELECT
        ROW_NUMBER() OVER(PARTITION BY tableD.col1 ORDER BY (tableD.someCol desc) AS "Row Number",
        col1,
        id
    FROM tableD
) tableB
ON tableA.id = tableB.id
WHERE some_clause_on_tableA_and_tableB
  AND tableB.[Row Number] = 1;

FROM子句中省略目標表並不意味着,但查詢本身可能會變得更加清晰,從而更容易發現潛在的問題。

或者,正如@mouters所建議的那樣,您可以將子選擇重寫為公用表表達式(CTE),或者實際上是一系列,例如,如果實際上tableD也是子查詢。 考慮一下:

WITH tableB AS (
    SELECT
        ROW_NUMBER() OVER(PARTITION BY tableD.col1 ORDER BY (tableD.someCol desc) AS "Row Number",
        col1,
        id
    FROM tableD
)
UPDATE tableA
    SET TableA.col1 = tableB.col1
FROM tableA INNER JOIN tableB /* or just: FROM tableB */
ON tableA.id = tableB.id
WHERE some_clause_on_tableA_and_tableB
  AND tableB.[Row Number] = 1;

同樣,將子選擇重寫為CTE沒有任何影響(不是在這種特殊情況下,因為您只引用了CTE一次),但這可能(或可能不是)有助於您找到問題的原因。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM