2

この質問は、カーソルに頼らずに未使用の連番範囲を発見することに関する以前の質問 (カーソルを使用しないSQL Server 2005 で連番を操作する ) のフォローアップです。SQL Server 2005 を使用しています。

これらの数値を使用して行う必要があるのは、これらの数値をテーブル内のレコードに割り当てることです。数字の表を、それらの数字を必要とするレコードと実際に関連付ける方法が思いつかないようです。

頭に浮かんだ考えられる解決策の 1 つは、ID を使用し、番号範囲の開始を ID シードとして使用して、一時テーブルにレコードを挿入することでした。このアプローチの唯一の問題は、番号の順序にギャップがあると、管理番号が重複してしまうことです。

これは私のテーブルがどのように見えるかです(過度に単純化されています):

数値表:

Number      
-------
102314
102315
102319
102320
102324
102329 

データ表:

CustomerId   PaymentAmt   ControlNumber
----------   ----------   -------------
1001         4502.01      NULL
1002         890.00       NULL
9830         902923.34    NULL

私はそれを作る方法が必要なので、最終的には次のようになります:

CustomerId   PaymentAmt   ControlNumber
----------   ----------   -------------
1001         4502.01      102314
1002         890.00       102315
9830         902923.34    102319

カーソルを使用しなくてもこれは可能ですか? 私がカーソルを避けている理由は、現在の実装がカーソルを使用しており、非常に遅い (12,000 レコードで 8 分) ため、代替手段を探していたからです。

注:回答を投稿してくれたすべての人に感謝します。それらはすべて素晴らしいものでした。私は、私の後に続く人のために、実装しやすく、維持しやすいと思われるものを選ぶ必要がありました。とても有難い。

4

5 に答える 5

6

これを試して:

;WITH CTE AS
(
    SELECT *, ROW_NUMBER() OVER(ORDER BY CustomerId) Corr
    FROM DataTable
)

UPDATE CTE
SET CTE.ControlNumber = B.Number
FROM CTE
JOIN (  SELECT Number, ROW_NUMBER() OVER(ORDER BY Number) Corr
        FROM NumberTable) B
ON CTE.Corr = B.Corr
于 2011-03-24T21:04:41.540 に答える
2

リンクされた質問からMartinのコードを構築すると、制御番号のないすべての行に行番号を付けることができます。次に、未使用のすべての数値に行番号を付けます。2 つのセットを結合すると、行ごとに一意の番号が得られます。

DECLARE @StartRange int, @EndRange int
SET @StartRange = 790123401
SET @EndRange = 790123450;

; WITH  YourTable(ControlNumber, CustomerId) AS
        (
        SELECT  790123401, 1000
        UNION ALL SELECT  790123402, 1001
        UNION ALL SELECT  790123403, 1002
        UNION ALL SELECT  790123406, 1003
        UNION ALL SELECT  NULL, 1004
        UNION ALL SELECT  NULL, 1005
        UNION ALL SELECT  NULL, 1006
        )
,       YourTableNumbered(rn, ControlNumber, CustomerId) AS
        (
        select  row_number() over (
                    partition by IsNull(ControlNumber, -1) 
                    order by ControlNumber)
        ,       *
        from    YourTable
        )
,       Nums(N) AS
        (
        SELECT @StartRange
        UNION ALL
        SELECT N+1
        FROM Nums
        WHERE N < @EndRange
        )
,       UnusedNums(rn, N) as
        (
        select  row_number() over (order by Nums.N)
        ,       Nums.N
        from    Nums
        where   not exists
                (
                select  *
                from    YourTable yt
                where   yt.ControlNumber = Nums.N
                )
        )
select  ytn.CustomerId
,       IsNull(ytn.ControlNumber, un.N)
from    YourTableNumbered ytn
left join
        UnusedNums un
on      un.rn = ytn.rn
OPTION (MAXRECURSION 0)          
于 2011-03-24T21:06:35.823 に答える
2

必要なのは、データ テーブルの決定論的な順序だけです。それがある場合はROW_NUMBER()、結合条件として使用できます。

with cte as (
  select row_number() over (order by CustomerId) as [row_number],
         ControlNumber
  from [Data Table]
         where ControlNumber is null),
    nte as (
  select row_number() over (order by Number) as [row_number],
         Number
  from [Numbers])
update cte
  set ControlNumber = Number
from cte 
join nte on  nte.[row_number] = cte.[row_number];

並行性の証明が必要な場合は、より複雑になります。

于 2011-03-24T21:08:03.397 に答える
1

usedUPDATE および DELETE の OUTPUT caluse を介して、@Number から値を削除するコードにEDITEDが追加されました。

それらを結合するために ROW_NUMBER() を使用してみてください:

DECLARE @Number table (Value int)
INSERT @Number VALUES (102314)
INSERT @Number VALUES (102315)
INSERT @Number VALUES (102319)
INSERT @Number VALUES (102320)
INSERT @Number VALUES (102324)
INSERT @Number VALUES (102329)

DECLARE @Data table (CustomerId int, PaymentAmt numeric(10,2),ControlNumber int)
INSERT @Data VALUES (1001,         4502.01      ,NULL)
INSERT @Data VALUES (1002,         890.00       ,NULL)
INSERT @Data VALUES (9830,         902923.34    ,NULL)

DECLARE @Used table (Value int)

;WITH RowNumber AS 
(
SELECT Value,ROW_NUMBER() OVER(ORDER BY Value) AS RowNumber FROM @Number

)
,RowData AS
(
SELECT CustomerId,ROW_NUMBER() OVER(ORDER BY CustomerId) AS RowNumber, ControlNumber FROM @Data WHERE ControlNumber IS NULL
)
UPDATE d
    SET ControlNumber=r.Value
    OUTPUT r.Value INTO @Used
    FROM RowData d
        INNER JOIN RowNumber r ON d.RowNumber=r.RowNumber

DELETE @Number WHERE Value IN (SELECT Value FROM @Used)

SELECT * FROM @Data
SELECT * FROM @Number

出力:

CustomerId  PaymentAmt                              ControlNumber
----------- --------------------------------------- -------------
1001        4502.01                                 102314
1002        890.00                                  102315
9830        902923.34                               102319

(3 row(s) affected)

Value
-----------
102320
102324
102329

(3 row(s) affected)
于 2011-03-24T21:06:27.140 に答える
0

2つのテーブルを結合するために何かが必要になります。2つのテーブル間で照合できるデータ値。

あなたの数字の表には、数字の1列だけではないものがあると思います。データテーブルに一致するものがそこにある場合は、更新を行うことができます。

カーソルを使用してデータテーブルをどのように更新していますか?

于 2011-03-24T21:00:03.007 に答える