2017-06-23 1 views
2

Je cours une requête qui me montre l'ID de certains éléments. Je connais la description de chaque article. J'ai donc 2 colonnes sur l'exécution d'une requêteSQL Server 2014 remplace la chaîne séparée par des virgules par des données de dictionnaire

Select 
    IdItem, 
    case 
     when IdItem = 'I' 
      then 'Injection' 
     when IdItem = 'P' 
      then 'Pill' 
     when IdItem = 'DI' 
      then 'DIU' 
     when IdItem = 'F' 
      then 'AQVF' 
     when IdItem = 'M' 
      then 'AQVM' 
     when IdItem = 'O' 
      then 'Other' 
     else 'Not Defined' 
    end as 'Description' 
from 
    dbo.Items 

La chose est que mon résultat parfois me montrer un résultat séparés par des virgules.

Quelque chose comme ceci:

IdItem | Description 
---------+------------ 
     P | Pill  
    M, O | Not Defined  
     DI | DIU  
M, P, DI | Not Defined 

Les résultats montre la description que non définie, à cause de l'autre, est-il un moyen pour que les résultats soient comme ça.

IdItem | Description 
---------+---------------- 
     P | Pill  
    M, O | AQVM, Other  
     DI | DIU  
M, P, DI | AQVM, Pill, DIU 

Dois-je utiliser un remplacement pour la chaîne, ou dois-je faire chaque combinaison le cas, comme

Select IdItem 
, case 
when IdItem = 'I' 
then 'Injection' 
when IdItem = 'P' 
then 'Pill' 
when IdItem = 'DI' 
then 'DIU' 
when IdItem = 'F' 
then 'AQVF' 
when IdItem = 'M' 
then 'AQVM' 
when IdItem = 'O' 
then 'Other' 
when IdItem = 'M, O' 
then 'AQVM, Other' 
when IdItem = 'M, P, DI' 
then 'AQVM, Pill, DIU' 
when IdItem = ...all other combinations 
then ...results 
else 'Not Defined' 
end 
as 'Description' 
from dbo.Items 

Répondre

1

Ces opérations sont généralement abordées avec une fonction qui sépare les valeurs de chaîne en utilisant une définition délimiteur. Si vous n'êtes pas sur SQL Server 2016+ et que vous ne pouvez pas utiliser le string_split intégré, vous devrez lancer le vôtre. Personnellement, je l'utilise:

create function [dbo].[StringSplit] 
(
    @str nvarchar(4000) = ' '    -- String to split. 
    ,@delimiter as nvarchar(1) = ','  -- Delimiting value to split on. 
    ,@num as int = null      -- Which value to return. 
) 
returns table 
as 
return 
(      -- Start tally table with 10 rows. 
    with n(n) as (select n from (values(1),(1),(1),(1),(1),(1),(1),(1),(1),(1)) n(n)) 
         -- 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(@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(@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,@str,s),0)-s,4000) from s) 
    select rn as ItemNumber 
      ,Item 
    from(select row_number() over(order by s) as rn 
       ,substring(@str,s,l) as item 
     from l 
     ) a 
    where rn = @num   -- Return a specific value where specified, 
     or @num is null  -- Or the everything where not. 
) 

qui est utilisé comme suit:

declare @Items table(IdItem nvarchar(50)); 
insert into @Items values('P'),('M, O'),('DI'),('M, P, DI, ZZZ'),('ZZZ'); 

declare @ItemDescripions table(ItemId nvarchar(50),ItemDescription nvarchar(50)); 
insert into @ItemDescripions values('I' ,'Injection'),('P' ,'Pill'),('DI','DIU'),('F' ,'AQVF'),('M' ,'AQVM'),('O' ,'Other'); 

select IdItem 
    ,ltrim(rtrim(s.Item)) as Item 
    ,isnull(d.ItemDescription,'Not Defined') as ItemDescription 
from @Items i 
    outer apply dbo.StringSplit(i.IdItem,',',null) s 
    left join @ItemDescripions d 
     on(ltrim(rtrim(s.Item)) = d.ItemId); 

Pour sortie:

+---------------+------+-----------------+ 
| IdItem  | Item | ItemDescription | 
+---------------+------+-----------------+ 
| P    | P | Pill   | 
| M, O   | M | AQVM   | 
| M, O   | O | Other   | 
| DI   | DI | DIU    | 
| M, P, DI, ZZZ | M | AQVM   | 
| M, P, DI, ZZZ | P | Pill   | 
| M, P, DI, ZZZ | DI | DIU    | 
| M, P, DI, ZZZ | ZZZ | Not Defined  | 
| ZZZ   | ZZZ | Not Defined  | 
+---------------+------+-----------------+ 

Si vous voulez afficher exactement vos ItemDescription valeurs que vous avez dans votre question (à laquelle je déconseillerais car cela viole les meilleures pratiques de base de données relationnelles sur ne pas stocker vos données dans les listes délimitées), vous pouvez utiliser un combo concaténer stuff et for xml à la place:

select i.IdItem 
     ,stuff((select ', ' + isnull(d.ItemDescription,'Not Defined') 
       from dbo.StringSplit(i.IdItem,',',null) s 
        left join @ItemDescripions d 
         on(ltrim(rtrim(s.Item)) = d.ItemId) 
       order by s.ItemNumber 
       for xml path('') 
       ) 
      ,1,2,'') as ItemDescription 
from @Items i; 

Pour sortie:

+---------------+------------------------------+ 
| IdItem  |  ItemDescription  | 
+---------------+------------------------------+ 
| P    | Pill       | 
| M, O   | AQVM, Other     | 
| DI   | DIU       | 
| M, P, DI, ZZZ | AQVM, Pill, DIU, Not Defined | 
| ZZZ   | Not Defined     | 
+---------------+------------------------------+