2017-02-06 1 views
2

Je suis en train d'écrire une procédure stockée qui vérifie si une chaîne contient des valeurs qui sont dans une autre table.Sql pour comparer une chaîne délimitée par rapport au tableau des valeurs connues pour trouver discordances

Je ne suis pas dans le contrôle de TableA et les données stockées dans cette colonne théorique de paquets est un ensemble délimité de mots. Pour démontrer, TableA contient une colonne, Paquets. Cette colonne contient une chaîne de paquets délimitée par des carets, E.G A^B signifierait que cette rangée a 2 paquets.

TableB est un contrôle de tableau I qui énumère les paquets disponibles.

Comme on peut le voir, TableA a quelques lignes qui ne disposent pas d'un paquet correspondant; D par exemple.

TableA

ID | Packages 
============ 
1 | A 
2 | A^B 
3 | C 
4 | A^B 
5 | A^C 
6 | D 
7 | C^D 

TableB

ID | Package 
============ 
91 | A 
92 | B 
93 | C 

Je suis en train d'écrire un script qui comparera les paquets dans TableA contre la liste connue du paquet dans TableB et sélectionnez une ligne de TableA qui fait ne pas avoir un paquet de soutien.

Une fois couru, je visais retourner un résultat similaire à cela,

TableAID | PackageNotSupported 
================================ 
6   | D 
7   | D 

Je ne peux pas vraiment montrer ce que je l'ai essayé jusqu'à présent parce que je ne sais pas où commencer. J'ai une fonction dans la base de données qui divisera une chaîne délimitée dans une table. Je peux l'employer contre les données xx^xx^xx mais je ne peux pas comprendre du tout comment joindre/comparer les chaînes.

J'ai essayé la solution trouvée dans ce post, How to compare multiple values in one column against a delimited string in a stored procedure mais n'a pas pu obtenir le résultat que je visais. En fin de compte SQL n'est pas mon fort et je n'ai pas la meilleure compréhension de la solution proposée dans ce post.

+0

est la colonne d'identification unique dans les deux tableaux? – scsimon

+0

Ref le close-vote. Quel autre site du réseau souhaiteriez-vous que je mette cette question de programmation? – Darren

+1

@ scsimon- oui, l'ID est unique dans les deux tables. Je vais modifier le Q pour refléter cela et éliminer toute confusion. – Darren

Répondre

3

Option 1 - Sans Parse/Fonction de Split

Declare @TableA table (ID int,Packages varchar(25)) 
Insert Into @TableA values 
(1 ,'A'), 
(2 ,'A^B'), 
(3 ,'C'), 
(4 ,'A^B'), 
(5 ,'A^C'), 
(6 ,'D'), 
(7 ,'C^D') 

Declare @TableB table (ID int,Package varchar(25)) 
Insert Into @TableB values 
(1 ,'A'), 
(2 ,'B'), 
(3 ,'C') 


Select A.ID 
     ,Package=B.RetVal 
From @TableA A 
Cross Apply (
       Select RetSeq = Row_Number() over (Order By (Select null)) 
         ,RetVal = LTrim(RTrim(B.i.value('(./text())[1]', 'varchar(max)'))) 
       From (Select x = Cast('<x>' + replace((Select replace(A.Packages,'^','§§Split§§') as [*] For XML Path('')),'§§Split§§','</x><x>')+'</x>' as xml).query('.')) as A 
       Cross Apply x.nodes('x') AS B(i) 
      ) B 
Left Join @TableB C on B.RetVal=C.Package 
Where C.Package is null 

Retours

ID Package 
6 D 
7 D 

Option 2 - Avec un Parse/Fonction de Split

Select A.ID 
     ,Package=B.RetVal 
From @TableA A 
Cross Apply [dbo].[udf-Str-Parse](A.Packages,'^') B 
Left Join @TableB C on B.RetVal=C.Package 
Where C.Package is null 

Parse UDF si vous êtes intéressé

CREATE FUNCTION [dbo].[udf-Str-Parse] (@String varchar(max),@Delimiter varchar(25)) 
Returns Table 
As 
Return ( 
    with cte1(N) As (Select 1 From (Values(1),(1),(1),(1),(1),(1),(1),(1),(1),(1)) N(N)), 
      cte2(N) As (Select Top (IsNull(DataLength(@String),0)) Row_Number() over (Order By (Select NULL)) From (Select N=1 From cte1 a,cte1 b,cte1 c,cte1 d) A), 
      cte3(N) As (Select 1 Union All Select t.N+DataLength(@Delimiter) From cte2 t Where Substring(@String,t.N,DataLength(@Delimiter)) = @Delimiter), 
      cte4(N,L) As (Select S.N,IsNull(NullIf(CharIndex(@Delimiter,@String,s.N),0)-S.N,8000) From cte3 S) 

    Select RetSeq = Row_Number() over (Order By A.N) 
      ,RetVal = LTrim(RTrim(Substring(@String, A.N, A.L))) 
    From cte4 A 
); 
--Orginal Source http://www.sqlservercentral.com/articles/Tally+Table/72993/ 
--Much faster than str-Parse, but limited to 8K 
--Select * from [dbo].[udf-Str-Parse-8K]('Dog,Cat,House,Car',',') 
--Select * from [dbo].[udf-Str-Parse-8K]('John||Cappelletti||was||here','||') 
+0

Des conneries! J'ai essayé tout ça sans l'udf-str-parse car je peux utiliser notre fonction split-string-into-a-table. Ils travaillent tous à merveille.Je vais aller lire sur "cross apply" donc j'ai une idée de ce que je suis copier/coller :) Merci John. – Darren

+0

@Darren Happy a aidé –

+0

@Darren CROSS APPLY est une fonctionnalité très puissante. Pensez-y comme une sous-routine. Dans ce cas, nous étendons votre enregistrement unique en plusieurs –