t-sql 在没有游标的情况下处理大量 SQL 行

t-sql process large set of SQL rows without cursor

我需要遍历 1600 万行 SQL 数据。由于性能问题,我被告知不要为此使用游标。我从 WHILE 循环开始,但我不知道如何使用 WHILE 循环获取 table 中的下一行。在下面查看我的进度。如何获取每行的 AccountNames 列?

DECLARE @rowId INT = 1;
DECLARE @RowCnt BIGINT = 0;
DECLARE @source varchar(8000);
DECLARE @current_source varchar(8000);
DECLARE @search varchar(8000) = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ';
DECLARE @replacement varchar(8000) = '22233344455566677778889999';
DECLARE @Converted varchar(8000) ;

SELECT @RowCnt = COUNT(0) FROM dbo.AccountNames;
select @source = AccountNumber FROM dbo.AccountNames where AccountNumber > ' ' order by Accountnumber;

WHILE @rowId <= 2
BEGIN

declare @i int, @iMax int;
set @iMax = len(@search);
set @i = 1;
while @i <= @iMax
begin
    set @Converted = replace(@source, substring(@search, @i, 1), substring(@replacement, @i, 1));
    set @i = @i + 1;
end

select @source = AccountNumber FROM dbo.AccountNames where AccountNumber > @current_source order by Accountnumber ;
print @source;
set @current_source = @source;
Set @rowId = @rowId + 1;
END

-编辑 感谢您的超快评论。我将根据评论部分的要求提供更多细节。

我需要从 AccountNames 中的每条记录中获取 AccountNumber 字段,将其转换为我的代码中显示的小键盘值,然后将该值插入到另一个 table 中,该 table 包含 AccountNumber 及其等效小键盘。如果游标对于这么大的 table 没问题,那么我将不胜感激有人向我展示正确的语法。

-编辑 2 我无法使用翻译,因为我使用的是 SQL Server 2016.

我找到了一种使用光标的方法。我不会打印帐号,而是将插入语句放入此代码的最终版本中。

DECLARE @rowId INT = 1;
DECLARE @AccountNum varchar(8000);
DECLARE @c cursor;
DECLARE @search varchar(8000) =      'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz';
DECLARE @replacement varchar(8000) = '2223334445556667777888999922233344455566677778889999';
DECLARE @Converted varchar(8000) ;


SET @c = cursor LOCAL FAST_FORWARD FOR SELECT AccountNumber 
FROM dbo.AccountNames 
where Accountnumber > 'DDDDDD' 
order by AccountNumber;

OPEN @c;
fetch next from @c into @AccountNum;

While @@fetch_status = 0
BEGIN
    print @AccountNum;
    declare @i int, @iMax int;
    set @iMax = len(@search);
    set @i = 1;
    while @i <= @iMax
    begin
        set @AccountNum = replace(@AccountNum, substring(@search, @i, 1), substring(@replacement, @i, 1));
        set @i = @i + 1;
    end

    print @AccountNum; --put insert statement here
    fetch next from @c into @AccountNum;

    set @rowId = @rowId + 1; --remove this test code after code is finished
    if @rowId > 1
    begin
        break
    end

END

close @c;
deallocate @c;

你可以用一个 SELECT 语句完成这一切:

DECLARE @search varchar(8000) =      'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz';
DECLARE @replacement varchar(8000) = '2223334445556667777888999922233344455566677778889999';

SELECT  AccountNumber,
        TRANSLATE(AccountNumber, @search, @replacement) AS TranslatedAcctNum
FROM    dbo.AccountNames 
WHERE   Accountnumber > 'DDDDDD' 
order by AccountNumber;

也可以很容易地变成单个 INSERT 语句。

作为一个额外的好处,它将 运行 快 10-1000 倍。

(注:没有任何测试数据,无法测试,所以可能有错别字,但应该很容易修复。)

虽然“翻译”答案显然是更优雅的解决方案,但如果您因为版本兼容性而无法使用它,您可以将其替换为嵌套的 REPLACE 语句。它仍然 运行 比游标或 while 循环快得多,并且结果可用于 INSERT 等集合操作。我在 SQL 2014 年对此进行了测试并且它有效,所以 2016 年应该没有问题

with cteSampleData as (
    SELECT * 
    FROM (VALUES ('CXE-34-A5'), ('52Q-A6-brxt'), ('kqed-pc-12ALE')
         ) as Accts(AccountNumber)
), cteTranslated as ( 
 SELECT AccountNumber
    , REPLACE(REPLACE(REPLACE(
      REPLACE(REPLACE(REPLACE(
      REPLACE(REPLACE(REPLACE(
      REPLACE(REPLACE(REPLACE(
      REPLACE(REPLACE(REPLACE(
      REPLACE(REPLACE(REPLACE(
      REPLACE(REPLACE(REPLACE(
      REPLACE(REPLACE(REPLACE(
      REPLACE(REPLACE(AccountNumber, 
         'A', '2'), 'B', '2'), 'C', '2'), 
         'D', '3'), 'E', '3'), 'F', '3'), 
         'G', '4'), 'H', '4'), 'I', '4'), 
         'J', '5'), 'K', '5'), 'L', '5'), 
         'M', '6'), 'N', '6'), 'O', '6'), 
         'P', '7'), 'Q', '7'), 'R', '7'), 'S', '7'), 
         'T', '8'), 'U', '8'), 'V', '8'), 
         'W', '9'), 'X', '9'), 'Y', '9'), 'Z', '9'
      ) as AcctTrans
 FROM cteSampleData
) --INSERT INTO DestTable (RawAcct, TranslatedAcct) 
SELECT AccountNumber, AcctTrans
FROM cteTranslated

编辑:输出如下所示:

AccountNumber AcctTrans
CXE-34-A5 293-34-25
52Q-A6-brxt 527-26-2798
kqed-pc-12ALE 5733-72-12253