Как соединить последовательные числа с несвязанными данными (SQL Server) - PullRequest
2 голосов
/ 24 марта 2011

Этот вопрос является продолжением предыдущего вопроса о том, как обнаружить неиспользуемые диапазоны последовательных чисел, не прибегая к курсорам ( Работа с последовательными числами в 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 записей), я искал альтернативы.

Примечание. Спасибо всем, кто опубликовал ответы.Все они были великолепны, я должен был выбрать тот, который казался более простым для реализации и простым в обслуживании для тех, кто придет за мной.Очень ценится.

Ответы [ 5 ]

6 голосов
/ 25 марта 2011

Попробуйте это:

;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
2 голосов
/ 25 марта 2011

Все, что вам нужно, это детерминированный порядок в таблице данных.Если у вас есть это, вы можете использовать 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];

Если вам нужно, чтобы это было доказательством совпадения, оно становится более сложным.

2 голосов
/ 25 марта 2011

Составляя код Мартина из связанного вопроса, вы могли бы дать всем строкам без контрольного номера номер строки.Затем присвойте всем неиспользованным номерам номер строки.Соедините два набора вместе, и вы получите уникальный номер в строке:

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)          
1 голос
/ 25 марта 2011

EDITED добавлено в код для удаления значений used из @Number через вызов OUTPUT для UPDATE и 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)
0 голосов
/ 25 марта 2011

Вам нужно что-то, чтобы соединить два стола вместе.Некоторые значения данных, которые вы можете сопоставить между двумя таблицами.

Я предполагаю, что в вашей таблице чисел есть нечто большее, чем один столбец чисел.Если там есть что-то, что вы можете сопоставить с вашей таблицей данных, вы можете получить обновление.

Как вы обновляете таблицу данных с помощью курсоров?

...