2017-10-10 122 views
0

我有兩個表,這樣比較兩個表並更新值在標誌列

`create table InputLocationTable(SKUID int,InputLocations varchar(100),Flag varchar(100)) 
create table Location(SKUID int,Locations varchar(100)) 

insert into InputLocationTable(SKUID,InputLocations) values(11,'Loc1, Loc2, Loc3, Loc4, Loc5, Loc6') 
insert into InputLocationTable(SKUID,InputLocations) values(12,'Loc1, Loc2') 
insert into InputLocationTable(SKUID,InputLocations) values(13,'Loc4,Loc5') 

insert into Location(SKUID,Locations) values(11,'Loc3') 
insert into Location(SKUID,Locations) values(11,'Loc4') 
insert into Location(SKUID,Locations) values(11,'Loc5') 
insert into Location(SKUID,Locations) values(11,'Loc7') 
insert into Location(SKUID,Locations) values(12,'Loc10') 
insert into Location(SKUID,Locations) values(12,'Loc1') 
insert into Location(SKUID,Locations) values(12,'Loc5') 
insert into Location(SKUID,Locations) values(13,'Loc4') 
insert into Location(SKUID,Locations) values(13,'Loc2') 
insert into Location(SKUID,Locations) values(13,'Loc2')` 

值我需要通過匹配每個表SKUID對得到的輸出,並更新標誌列中的值如截圖所示,我已經試過這樣的事情代碼

`SELECT STUFF((select ','+ Data.C1 
FROM 
(select 
    n.r.value('.', 'varchar(50)') AS C1 
from InputLocation as T 
    cross apply (select cast('<r>'+replace(replace(Location,'&','&'), ',', '</r><r>')+'</r>' as xml)) as S(XMLCol) 
    cross apply S.XMLCol.nodes('r') as n(r)) DATA 
WHERE data.C1 NOT IN (SELECT Location 
       FROM Location) for xml path('')),1,1,'') As Output` 

但不相信有輸出,並且還我試圖避免XML路徑代碼,因爲性能並不第一名這段代碼,我需要的輸出像下面的截圖一樣。任何幫助將不勝感激。

enter image description here

+0

你的意思是說,更新的標誌的列,其中INputLocation不是位置表的位置scolumn –

+0

我不知道如果我正確地理解你的問題......你說,你設法找到與XML解決方案但寧願避免使用它。那麼,「FOR XML PATH」afaik是直到SQL Server 2016執行字符串連接的最佳和推薦的解決方案。2016年,MSFT添加了STRING_AGG函數。在SQL Server 2008上,您可以使用自定義程序集作爲替代方案。但這有其不利之處。看看https://www.sqlshack.com/string-concatenation-done-right-part-2-an-effective-technique/。 –

+0

嗨,感謝您的重播,我只是避免使用XML路徑,這並不意味着我不應該使用和所有,我使用的SQL服務器2014年,所以請建議我更好的代碼或答案爲 – Karthik

回答

0

我認爲你需要先了解一下,爲什麼你認爲XML方法不執行不夠好,您的需求,爲it has actually been shown to perform very well for larger input strings

如果只需要處理的輸入串高達要麼4000或8000個字符(分別非maxnvarcharvarchar類型),則可以利用包含內嵌表值函數which will also perform very well內的帳簿表。我使用的版本可以在這篇文章的末尾找到。

利用這個功能,我們可以在你的InputLocations柱拆分出來的價值觀,但我們仍然需要使用for xml將它們串聯到一起爲你想要的格式:

-- Define data 
declare @InputLocationTable table (SKUID int,InputLocations varchar(100),Flag varchar(100)); 
declare @Location table (SKUID int,Locations varchar(100)); 

insert into @InputLocationTable(SKUID,InputLocations) values (11,'Loc1, Loc2, Loc3, Loc4, Loc5, Loc6'),(12,'Loc1, Loc2'),(13,'Loc4,Loc5'),(14,'Loc1'); 
insert into @Location(SKUID,Locations) values (11,'Loc3'),(11,'Loc4'),(11,'Loc5'),(11,'Loc7'),(12,'Loc10'),(12,'Loc1'),(12,'Loc5'),(13,'Loc4'),(13,'Loc2'),(13,'Loc2'),(14,'Loc1'); 

--Query 

-- Derived table splits out the values held within the InputLocations column 
with i as 
(
    select i.SKUID 
      ,i.InputLocations 
      ,s.item as Loc 
    from @InputLocationTable as i 
     cross apply dbo.fn_StringSplit4k(replace(i.InputLocations,' ',''),',',null) as s 
) 
select il.SKUID 
     ,il.InputLocations 
     ,isnull('Add ' -- The split Locations are then matched to those already in @Location and those not present are concatenated together. 
       + stuff((select ', ' + i.Loc 
         from i 
          left join @Location as l 
           on i.SKUID = l.SKUID 
            and i.Loc = l.Locations 
         where il.SKUID = i.SKUID 
          and l.SKUID is null 
         for xml path('') 
        ) 
        ,1,2,'' 
        ) 
       ,'No Flag') as Flag 
from @InputLocationTable as il 
order by il.SKUID; 

輸出:

+-------+------------------------------------+----------------------+ 
| SKUID |   InputLocations   |   Flag   | 
+-------+------------------------------------+----------------------+ 
| 11 | Loc1, Loc2, Loc3, Loc4, Loc5, Loc6 | Add Loc1, Loc2, Loc6 | 
| 12 | Loc1, Loc2       | Add Loc2    | 
| 13 | Loc4,Loc5       | Add Loc5    | 
| 14 | Loc1        | No Flag    | 
+-------+------------------------------------+----------------------+ 

對於nvarchar輸入(我有不同的功能varcharmax類型輸入)這是我的版本的字符串分裂功能鏈接上面:

create function [dbo].[fn_StringSplit4k] 
(
    @str nvarchar(4000) = ' '  -- String to split. 
,@delimiter as nvarchar(1) = ',' -- Delimiting value to split on. 
,@num as int = null    -- Which value in the list to return. NULL returns all. 
) 
returns table 
as 
return 
    -- Start tally table with 10 rows. 
with n(n) as (select 1 union all select 1 union all select 1 union all select 1 union all select 1 union all select 1 union all select 1 union all select 1 union all select 1 union all select 1) 

    -- Select the same number of rows as characters in @str as incremental row numbers. 
    -- Cross joins increase exponentially to a max possible 10,000 rows to cover largest @str length. 
    ,t(t) as (select top (select len(isnull(@str,'')) a) row_number() over (order by (select null)) from n n1,n n2,n n3,n n4) 

    -- Return the position of every value that follows the specified delimiter. 
    ,s(s) as (select 1 union all select t+1 from t where substring(isnull(@str,''),t,1) = @delimiter) 

    -- Return the start and length of every value, to use in the SUBSTRING function. 
    -- ISNULL/NULLIF combo handles the last value where there is no delimiter at the end of the string. 
    ,l(s,l) as (select s,isnull(nullif(charindex(@delimiter,isnull(@str,''),s),0)-s,4000) from s) 

select rn 
     ,item 
from(select row_number() over(order by s) as rn 
      ,substring(@str,s,l) as item 
     from l 
    ) a 
where rn = @num 
    or @num is null; 
go