2

这个问题是我之前关于发现未使用的序列号范围而无需使用游标的问题的后续问题(在没有游标的情况下使用 SQL Server 2005 中的序列号)。我正在使用 SQL Server 2005。

我需要对这些数字做的是将这些数字分配给表中的记录。我似乎无法想出一种方法来实际将数字表与需要这些数字的记录相关联。

想到的一种可能的解决方案是使用标识将记录插入临时表中,并将数字范围的开头用作标识种子。这种方法的唯一问题是,如果数字序列中有间隙,那么我最终会得到重复的控制数字。

这就是我的表格的样子(过于简化):

数字表:

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

这是否可能无需使用游标?我避免使用游标的原因是因为我们当前的实现使用游标,而且由于它太慢(8 分钟超过 12,000 条记录),我一直在寻找替代方案。

注意:感谢所有发布答案的人。他们都很棒,我必须选择一个看起来更容易实现和最容易维护的那个,无论是谁在我之后。非常感激。

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

根据链接问题中的马丁代码,您可以为所有没有控制编号的行提供行号。然后给所有未使用的数字一个行号。将这两组连接在一起,每行都有一个唯一的数字:

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

EDITED在代码中添加以used从@Number 中删除值,通过 UPDATE 的 OUTPUT caluse 和 DELETE

尝试使用 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

你需要一些东西来将两张桌子连接在一起。您可以在两个表之间匹配的一些数据值。

我假设您的数字表不仅仅是一列数字。如果其中有任何内容可以与您的数据表匹配,则可以进行更新。

您如何使用游标更新数据表?

于 2011-03-24T21:00:03.007 回答