2016-07-30 1 views
1

Je tente de créer une vue SQL qui renverra une valeur concaténée des sous-chaînes à partir d'une colonne dans une table.Retour des sous-chaînes concaténées de la colonne dans SQL

Dans mon exemple, il y a une colonne intitulée 'DefDetails' dans une table nommée 'TrebuchetSettings', qui contient une liste XML de valeurs que j'ai besoin de concaténer ensemble.

La colonne DefDetails tiendra une valeur comme celui ci-dessous, par enregistrement:

<Trebuchet> <FolderSetDef ID="9365da81288308c9c57aba483f83d2469a5da9ecba" Name="ReportDef" Version="1.0" SubType="" Scope="Global" Culture="Invariant" View="(None)"> <Alias /> <Description /> <Owner>934ec7a1701c451ce57f2c43bfbbe2e46fe4843f81</Owner> <FolderList> <FolderDef ID="93af31dc1b3238241be33549ba8f8239b377767680" Name="Yearly Reports" ParentID="93af31a36cf8232f44265b40f9a1cd14d1e7000813" Scope="Core" /> <FolderDef ID="93af31a36cf8232f44265b40f9a1cd14d1e7000813" Name="CSM Management Reports" ParentID="Root" Scope="Core" /> </FolderList> </FolderSetDef> </Trebuchet>

l'aide d'une instruction SQL, je dois interroger la table TrebuchetSettings et retourner une liste concaténée du « Nom » champs dans les noeuds 'FolderDef' dans le XML ci-dessus, séparés par un caractère '/', avec FolderDef dont les ID correspondent à un ParentID des FolderDef suivants listés au début de la chaîne, de sorte que la structure concaténée représente une structure de dossier.

Comme il existe d'autres types d'enregistrements dans cette table, ma requête se compose actuellement de ce qui suit, pour identifier les documents que je dois tirer ces sous-chaînes de:

SELECT * 
FROM TrebuchetSettings 
WHERE DefType = 'FolderSetDef' 
AND DefDetails LIKE '%(Folder ID)%' 

Dans l'exemple SQL ci-dessus, le dossier ID est un ID de 42 caractères qui sera comparé à une valeur d'une autre table pour correspondre à l'ID de l'un des dossiers Defs dans le XML.

Malheureusement, je n'ai pas de jeu de code de départ pour cela, car je n'ai pas l'expérience de travailler avec des sous-chaînes d'une colonne en SQL et je ne sais pas par où commencer.

+0

Je vous suggère de déplacer/copier 'valeur NAME' dans une colonne séparée et définir une colonne de drapeau pour les lignes où' DefDetails LIKE « % (ID de dossier)% ''. Sinon, ce sera une opération très lente. SQL n'est pas le meilleur outil pour travailler avec XML. –

Répondre

1

Ce que vous essayez de faire peut-être très lent s'il y a beaucoup de données ... Dans ce cas, il serait un bon conseiller pour administrer un (déclenché?) table secondaire où vous tenez vos ParentIDs dans une colonne indexée avec une clé à votre ligne XML contenant. C'est - en d'autres termes - quelque chose comme un index auto-réalisé ...

Juste pour que cela soit clair: Vous avez une table avec plusieurs identifiants (chaînes longues). Ensuite, vous devez trouver toutes les entrées XML qui contiennent cette valeur comme "ParentID" dans "/ FolderDef". Si vous en trouvez un, vous voulez que tous les noms des DefDetails spécifiques soient concaténés. Cela signifie: Pour tout ID dans votre deuxième tableau, vous devrez scanner tous les DefDetails encore et encore ... Une recherche LIKE avec un % au début sera très lent. La méthode XML .exist() devrait être plus rapide ...

Vous pouvez essayer ceci:

Je déclare une variable de table pour se moquer de vos paramètres table avec deux entrées:

DECLARE @TrebuchetSettings TABLE(DefDetails XML); 
INSERT INTO @TrebuchetSettings VALUES 
(N'<Trebuchet> 
    <FolderSetDef ID="9365da81288308c9c57aba483f83d2469a5da9ecba" Name="ReportDef" Version="1.0" SubType="" Scope="Global" Culture="Invariant" View="(None)"> 
     <Alias /> 
     <Description /> 
     <Owner>934ec7a1701c451ce57f2c43bfbbe2e46fe4843f81</Owner> 
     <FolderList> 
      <FolderDef ID="93af31dc1b3238241be33549ba8f8239b377767680" Name="Yearly Reports" ParentID="93af31a36cf8232f44265b40f9a1cd14d1e7000813" Scope="Core" /> 
      <FolderDef ID="93af31a36cf8232f44265b40f9a1cd14d1e7000813" Name="CSM Management Reports" ParentID="Root" Scope="Core" /> 
     </FolderList> 
    </FolderSetDef> 
</Trebuchet>') 
,(N'<Trebuchet> 
    <FolderSetDef ID="SomeOther" Name="ReportDef" Version="1.0" SubType="" Scope="Global" Culture="Invariant" View="(None)"> 
     <Alias /> 
     <Description /> 
     <Owner>OtherOwner</Owner> 
     <FolderList> 
      <FolderDef ID="Other first ID" Name="Yearly Reports" ParentID="Other ParentID" Scope="Core" /> 
      <FolderDef ID="Other second ID" Name="CSM Management Reports" ParentID="Root" Scope="Core" /> 
     </FolderList> 
    </FolderSetDef> 
</Trebuchet>'); 

Définir votre deuxième table avec un ParentID existant et on n'existant

DECLARE @YourOtherTable TABLE(FolderID VARCHAR(42)); 
INSERT INTO @YourOtherTable VALUES 
('93af31a36cf8232f44265b40f9a1cd14d1e7000813') 
,('Some not existing'); 

Maintenant trouver tous les enregistrements avec un FolderDef-ParentID donné et liste tous les attributs de nom en tant que / -sparated list

SELECT ot.FolderID 
     ,concatenated.Names 
FROM @YourOtherTable AS ot 
CROSS JOIN @TrebuchetSettings AS s 
CROSS APPLY 
(
    SELECT STUFF(
    (
    SELECT '/' + A.NameAttr.value('@Name','varchar(max)') 
    FROM DefDetails.nodes('/Trebuchet/FolderSetDef/FolderList/FolderDef') AS A(NameAttr) 
    FOR XML PATH('') 
    ),1,1,'') 
) AS concatenated(Names) 
WHERE s.DefDetails.exist('/Trebuchet/FolderSetDef/FolderList/FolderDef[@ParentID=sql:column("ot.FolderID")]')=1 

Le résultat pour ce serait:

93af31a36cf8232f44265b40f9a1cd14d1e7000813 Yearly Reports/CSM Management Reports