2014/4/25

[SQL] SQL 中的 foreach 做法

SQL 沒有 foreach。如果我們想在 SQL 指令中使用 foreach, 只能使用變通和模擬的方法。以下只是我的個人記事而已。這個做法源自於以下的一篇問答: http://stackoverflow.com/questions/18513986/how-to-write-a-foreach-in-sql-server

先來看程式:

-- Reference: http://stackoverflow.com/questions/18513986/how-to-write-a-foreach-in-sql-server
DECLARE @I INT = 0
DECLARE @PERSON nvarchar(20)
DECLARE @TEMPPERSON nvarchar(20)
DECLARE @TEMPSECURITY nvarchar(1024)
DECLARE MY_CURSOR CURSOR LOCAL STATIC READ_ONLY FORWARD_ONLY

FOR 
SELECT CAST([RetailerId] AS nvarchar)+[LastName]+[FirstName] FROM [BoData].[General].[Person] WHERE [BoardNo] IS NULL

OPEN MY_CURSOR
FETCH NEXT FROM MY_CURSOR INTO @PERSON

WHILE @@FETCH_STATUS = 0
    BEGIN 
        SET @TEMPPERSON = ''
        SELECT @TEMPPERSON = (CAST([RetailerId] AS nvarchar)+[LastName]+[FirstName]), @I = @I + 1
        FROM [Person]  
        WHERE ([BoardNo] IS NOT NULL) AND (CAST([RetailerId] AS nvarchar) = SUBSTRING(@PERSON, 0, 9)) AND 
        ([LastName]+[FirstName] = SUBSTRING(@PERSON, 9, 20))
        IF @TEMPPERSON != ''
            BEGIN
                PRINT CAST(@I AS nvarchar) + '.' + char(9) + @PERSON + char(9) + @TEMPPERSON
            END
        FETCH NEXT FROM MY_CURSOR INTO @PERSON
    END
CLOSE MY_CURSOR
DEALLOCATE MY_CURSOR

這個程式的目的, 在於找出資料庫中重複的資料(同一個經銷商號碼、同一個名字, 只有身分不同 -- 例如身兼老闆和聯絡人, 他填寫了兩份申請文件。所以這種重複是合理的)。但是由於資料的輸入來源不同, 所以其中一筆有填 BoardNo 欄位, 另一筆沒有。我想做的, 就是查出到底資料庫有多少筆像這類的重複資料, 我可能會拿這個資訊做後續處理, 例如把重複者刪除, 或者幫他們填入那個相同的 BoardNo 資料。

不管我後面打算怎麼做, 我得先把他們找出來, 否則一切免談。我查到了一個可以在 SQL 中模擬 foreach 的做法, 就是如上的程式。如果你沒有用過這種做法, 它看起來實在不太容易了解, 不過基本上, 我的做法就是先從資料庫中撈出 BoardNo IS NULL 的所有記錄 (在程式中沒有這個變數, 我暫且將它稱為「原始列表」), 然後透過 FOR ... OPEN ... FETCH ... WHILE 這種語法, 模擬出一個 foreach 迴圈。若使用抽象的表達方式, 就是:

foreach (@PERSON in 原始列表) {
   ...
}

如果要對擷取出來的資料做些動作, 就寫在最裡面的那個 IF 區段裡面 (也就是 PRINT ... 那一行)。

也許是因為語法的限制, 我發現我似乎沒辦法使用多於一個欄位的 entry, 所以我才使用 CAST([RetailerId] AS nvarchar)+[LastName]+[FirstName] 把三個欄位包成一個欄位, 然後在後面把它們分別拆出來用。或許還有更簡單的做法也不一定, 我想再找找看。

沒有留言:

張貼留言