0

このクエリ(プロトタイプ)を使用してtableDからデータを取得して、tableAのcol1をUPDATEしようとしています:

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;

残念ながら、これは正しく機能しません (誤った更新) が、#temp テーブルに tableB のデータを明示的に格納し、その #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;

後者が機能する理由はわかりませんが、最初は機能しません。最初のクエリでは、ネストされた 2 つのサブクエリ (行ランキング付き) が正しいデータを取得できないようですが、間違っている可能性があります。どんな助けでも大歓迎です!!!

ありがとう、サチン

4

2 に答える 2

2

tableD で参照されている tableA ID をグループ化するために、partition と order by キーワードを使用する OVER 句がおそらく欠落しているように感じます。基本的に、あなたがやろうとしているのは、tableA の各 ID の tableD で見つかった最初の行で、tableA で見つかった各エントリを更新することです。

おそらく、あなたの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
于 2012-05-19T20:14:22.387 に答える
0

例でカバーされていない何かがあるに違いありません。つまり、提示された2つの方法は互いに同等です。しかし、実際のクエリがより複雑に見える場合は、それよりもどういうわけか実際の問題を確認できない可能性があります。

問題をより早く発見できるように、1つのレベルのネストを取り除くことでクエリを簡略化できます。次のように、[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;

さらに、実際には新しいエイリアスを割り当てていないため、次のようにUPDATEステートメントtableAの句からエイリアスを省略できます。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を1回しか参照していないため)、これは、それ自体で、検索に役立つ場合があります(またはそうでない場合もあります)。問題の原因。

于 2012-05-21T20:10:17.683 に答える