4

@@バージョン 1

SQL Server 2008 を使用して、値を列にカスケードしようとしています。グループ ID (GID) と、グループ内のレコードの順序を含む Seq を持つテーブルがあります。存在する列、この場合は名前と給与 - 私の実際のテーブルには 50 を超える列があり、それらに NULL が含まれている場合、その列の前の行の値で NULL 値を更新する必要があります。

これを説明するものを次に示します。

GID Seq Name    Salary
1   1   James   NULL
1   2   NULL    100
1   3   NULL    NULL
2   1   NULL    81
2   2   Smith   NULL
2   3   NULL    NULL
3   1   Charles NULL
3   2   NULL    NULL
3   3   Brown   NULL
3   4   NULL    75
4   0   Ron 50
4   1   NULL    20
4   2   NULL    NULL

私の結果は次のようになります。

GID Seq Name    Salary
1   1   James   NULL
1   2   James   100
1   3   James   100
2   1   NULL    81
2   2   Smith   81
2   3   Smith   81
3   1   Charles NULL
3   2   Charles NULL
3   3   Brown   NULL
3   4   Brown   75
4   0   Ron 50
4   1   Ron 20
4   2   Ron 20

動的 SQL、ループ、またはカーソルを使用せずにこれを実行しようとしています。

簡単なテスト ケースのコード:

DECLARE @Test TABLE (GID int, Seq int, Name varchar(50), Salary decimal) 

INSERT INTO @Test VALUES (1, 1, 'James', NULL)
INSERT INTO @Test VALUES (1, 2, NULL, 100.40)
INSERT INTO @Test VALUES (1, 3, NULL, NULL)
INSERT INTO @Test VALUES (2, 1, NULL, 80.50)
INSERT INTO @Test VALUES (2, 2, 'Smith', NULL)
INSERT INTO @Test VALUES (2, 3, NULL, NULL)
INSERT INTO @Test VALUES (3, 1, 'Charles', NULL)
INSERT INTO @Test VALUES (3, 2, NULL, NULL)
INSERT INTO @Test VALUES (3, 3, 'Brown', NULL)
INSERT INTO @Test VALUES (3, 4, NULL, 75)
INSERT INTO @Test VALUES (4, 0, 'Ron', 50)
INSERT INTO @Test VALUES (4, 1, NULL, 20)
INSERT INTO @Test VALUES (4, 2, NULL, NULL)

SELECT * FROM @Test

@@Version 2 @@Version 1 の解決策を提供してくれた GilM に感謝します。問題に少し追加しました。Seq 列の開始番号は 0 または 1 のいずれかです。最初の問題の解決策では、再帰 CTE のアンカーが 1 を参照しています。1 または 0 の場合はどうなるでしょうか? このバージョンでは、最後の 3 行のデータ (GID = 4) が上記の 3 つのコード ブロックすべてに追加されました。

ありがとう!

4

2 に答える 2

2

これはどう?:

;WITH CTE AS (
SELECT GID, SEQ, Name, Salary
FROM @Test t1
WHERE SEQ = (SELECT MIN(SEQ) FROM @Test t2 WHERE t2.GID = t1.GID)
UNION ALL
SELECT t.GID, t.SEQ, COALESCE(t.Name,c.Name), COALESCE(t.Salary,c.Salary)
FROM CTE c
JOIN @Test t ON t.GID = c.GID AND t.SEQ = c.SEQ+1
)
UPDATE t SET 
    Name = c.Name,
    Salary =  c.Salary
FROM @Test t
JOIN CTE c ON c.GID = t.GID AND c.Seq = t.SEQ
于 2012-08-02T21:42:55.613 に答える
1
update T set
  Name =   (
           select top(1) T1.Name
           from @Test as T1
           where T1.GID = T.GID and
                 T1.Seq <= T.Seq and
                 T1.Name is not null
           order by T1.Seq desc
           ),
  Salary = (
           select top(1) T1.Salary
           from @Test as T1
           where T1.GID = T.GID and
                 T1.Seq <= T.Seq and
                 T1.Salary is not null
           order by T1.Seq desc
           )
from @Test as T
where T.Name is null or 
      T.Salary is null

50列の場合、多くの入力と多くの相関サブクエリがあります。

代わりにXMLを使用するバージョンがあります。タイピングとパフォーマンスが少ないほど良いかもしれません。

with C as
(
  select GID,
         (
         select *
         from @Test as T2
         where T1.GID = T2.GID
         order by T2.Seq desc
         for xml path('row'), type
         ) as X
  from @Test as T1
  group by GID
)
update T set
       Name   = C.X.value('(/row[Seq<=sql:column("T.Seq")]/Name)[1]',   'varchar(50)'),
       Salary = C.X.value('(/row[Seq<=sql:column("T.Seq")]/Salary)[1]', 'decimal')
from @Test as T
  inner join C 
    on T.GID = C.GID

SE-データ

于 2012-08-03T06:08:11.780 に答える