2017-04-25 126 views
0

我在Table1中有幾個字符串,我想根據表2中的值進行更新。SQL Server拼圖 - 在逗號之前複製逗號並替換字符串?

示例代碼

http://rextester.com/HQFOQ18215

IF OBJECT_ID('Test1','U') iS NOT NULL 
DROP TABLE Test1; 

IF OBJECT_ID('Test2','U') iS NOT NULL 
DROP TABLE Test2; 


Create table Test1 
(
Id   INT 
,Lid  INT 
,MyString VARCHAR(MAX) 
,Did  INT 
,Secid  INT 
); 

INSERT INTO Test1 values (1,100,'you,shall,not,pass,gandlaf,the,grey', 401, 501); 
INSERT INTO Test1 values (2,100,'ok,fine,bye', 401, 501); 
INSERT INTO Test1 values (3,100,'test,dev,uat,prod', 403, 501); 
INSERT INTO Test1 values (4,100,'1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16', 404, 501); 


Create table Test2 
(
Id    INT IDENTITY(1,1) 
,SecId   INT 
,CommaPosition INT 
,Value   VARCHAR(50) 
,Did   INT 
,RowId   INT 
); 

INSERT INTO Test2 Values (501, 4, '[Quantity]', 401, 1); 
INSERT INTO Test2 Values (501, 14, '[Price]', 401, 1); 
INSERT INTO Test2 Values (501, 4, '[Quantity]', 401, 2); 
INSERT INTO Test2 Values (501, 14, '[Price]', 401, 2); 
INSERT INTO Test2 Values (501, 14, '[Quantity|Price]', 403, 3); 
INSERT INTO Test2 Values (501, 4, '[Interest]', 404, 4); 
INSERT INTO Test2 Values (501, 14, '[Expired]', 404, 4); 

SELECT * FROM Test1; 
SELECT * FROM Test2; 

期望輸出

/* 

Expected OUTPUT 

Id Lid  MyString             Did  Secid 
1 100  you,shall,not,[quantity],gandlaf,the,grey,,,,,,,[Price], 401  501 
2 100  ok,fine,bye,[quantity],,,,,,,,,,[Price],     402  501 
3 100  test,dev,uat,prod,,,,,,,,,,[Quantity|Price],    403  501 
4 100  1,2,3,[Quantity],5,6,7,8,9,10,11,12,13,[Price],15,16  404  501 
*/ 
  1. 第一串you,shall,not,pass,gandlaf,the,grey其中"pass"是之前其通過[quantity]從表2但是這並未替換第四逗號位置't h ave第14個逗號 所以逗號被複制直到它到達第14個逗號並且在第14個逗號[Price]被替換之前。最終輸出是"you,shall,not,[quantity],gandlaf,the,grey,,,,,,,[Price],"

  2. 第二個字符串ok,fine,bye沒有逗號第四十四任逗號,所以第4逗號添加和[quantity]之前在表2和最終被取代,然後加逗號,直到第14位的逗號位置列 BASD字符串將成爲ok,fine,bye,[quantity],,,,,,,,,,[Price],

  3. 三串test,dev,uat,prod只有14逗號位置表2中可用,因此逗號被複制,直到14日逗號和14逗號之前[Quantity|Price]串 加入最終的字符串變成test,dev,uat,prod,,,,,,,,,,[Quantity|Price],

  4. 在第四根弦1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16如果你看到第4和第14次成爲逗號可用,因此14日逗號之前的字符串被替換[Interest]和字符串成爲14逗號被 [Expired]替換而將餘下的字符串不變。

我想實現上面的輸出,我試過下面的update語句沒有給我想要的結果。

UPDATE T1 
SET T1.MyString = T1.MyString + REPLICATE(',',T2.CommaPosition - (len(T1.MyString) - LEN(REPLACE(T1.MyString,',','')))) 
FROM Test1 as T1 INNER JOIN Test2 as T2 ON T1.Secid = T2.SecId AND T1.Did = T2.Did AND T1.Id = T2.RowId; 

SELECT DISTINCT T1.Lid, T1.MyString, T1.Did, T1.Secid, T2.RowId 
FROM Test1 as T1 INNER JOIN Test2 as T2 ON T1.Secid = T2.SecId AND T1.Did = T2.Did AND T1.Id = T2.RowId; 
+1

這根本沒有任何意義。爲什麼你首先有這些奇怪的分隔字符串?這違反了1NF並且破壞了關係數據的整個觀點。 –

回答

2

我假設你執行某種宏替換。

一對夫婦的注意事項:

  1. 後面的逗號似乎是不一致的,所以我離開它
  2. 你有價格的最後一排,而我有過期

示例

Select A.ID 
     ,A.Lid 
     ,B.MyString 
     ,A.Did 
     ,A.Secid 
From Test1 A 
Cross Apply (
       Select MyString = Stuff((Select ',' +RetVal 
        From (
          Select RetSeq 
           ,RetVal = max(IsNull(B2.Value,B1.RetVal)) 
          From (
            Select Top (Select max(CommaPosition) From Test2 Where RowID=A.ID) 
              RetSeq=Row_Number() Over (Order By (Select null)) 
              ,RetVal='' 
            From master..spt_values 
            Union All 
            Select RetSeq = Row_Number() over (Order By (Select null)) 
              ,RetVal = LTrim(RTrim(N.i.value('(./text())[1]', 'varchar(max)'))) 
            From (Select x = Cast('<x>' + replace((Select replace(A.MyString,',','§§Split§§') as [*] For XML Path('')),'§§Split§§','</x><x>')+'</x>' as xml).query('.')) as X 
            Cross Apply x.nodes('x') AS N(i) 
           ) B1 
          Left Join Test2 B2 on B2.RowID=A.ID and B2.CommaPosition=B1.RetSeq 
          Group By B1.RetSeq 
         ) B3 
        Order by RetSeq 
        For XML Path ('')),1,1,'') 
      ) B 

返回

enter image description here

2

正確答案是不中存儲多個值一列。這違反了第一範式 !!!

如果將連接的字符串分解爲父表和子表,最好。您的示例Table2看起來是一組修改命令,它已經具有所需的結構 - 您只需將全套值放入永久表中即可。

一旦你有了這些,處理你的變化數據是非常簡單的:加入關鍵值和更新!繁榮,完成。您的數據庫應該進行規範化處理,不應該將數據以易於修改的數據存儲在需要解壓縮,修改並重新打包的格式中。

如果您需要某種方法將數值連接在一起以產生如MyString的輸出Table1,請爲此查看,或者在前端代碼中執行此操作。有一個很好的基於SQL的解決方案,可以很容易地做到這一點。謹防隨機XML PATH您可能遇到的解決方案,因爲大多數解決方案無法容納包含類似xml的元素的字符串,例如><。使用下面這個例子中的一個(用.value()表達式完成),其中可以使用來容納這樣的字符。

這是一個通用示例,顯示如何將父表和子表合併到單個行中,每個父表與每個父表中的所有子值連接在一起。您可以使用FOR XMLORDER BY子句放入查詢中以獲取特定順序。

CREATE TABLE dbo.Parent (
    ParentId int identity(1,1) NOT NULL CONSTRAINT PK_Parent PRIMARY KEY CLUSTERED, 
    Name varchar(100) NOT NULL CONSTRAINT UQ_Parent_Name UNIQUE 
); 

CREATE TABLE dbo.ParentChild (
    ParentId int NOT NULL, 
    ChildName varchar(100) 
); 

INSERT dbo.Parent (Name) VALUES 
    ('Parent 1'), ('Parent X'), ('Parent B'); 

INSERT dbo.ParentChild (ParentId, ChildName) VALUES 
    (1, 'ABC'), (1, 'WHOAMAN'), (1, 'QRT'), 
    (2, 'XYZ'), (3, 'LMN'), (3, 'MAN'), (3, 'WHOADOG'); 

SELECT 
    p.*, 
    Children = Substring((
     SELECT ', ' + ChildName 
     FROM ParentChild pc 
     WHERE p.ParentId = pc.ParentId 
     FOR XML PATH(''), TYPE 
    ).value('.[1]', 'varchar(max)'), 3, 8000) 
FROM 
    dbo.Parent p 
WHERE -- an example of filtering by a child value without substrings on the combined string 
    EXISTS (
     SELECT * 
     FROM dbo.ParentChild pc 
     WHERE 
     p.ParentId = pc.ParentId 
     AND pc.ChildName = 'WHOADOG' 
    );