J'ai une table qui définit une hiérarchie:requête SQL: hiérarchique Coalesce
Create Table [example] (
id Integer Not Null Primary Key,
parentID Integer Null,
largeData1 nVarChar(max) Null,
largeData2 nVarChar(max) Null);
-- largeData3...n also exist
Insert Into [example] (id, parentID, largeData1, largeData2)
Select 1, null, 'blah blah blah', null Union
Select 2, 1, null, null Union
Select 3, 1, 'foo bar foobar', null Union
Select 4, 3, null, 'lorem ipsum' Union
Select 5, 4, null, null;
diagramme Hiérarchie pour ces données:
Je veux écrire une requête qui renverra un seul row pour toute valeur [id] donnée. La ligne doit contenir les informations [id] et [parentID] de cette ligne. Il devrait également contenir les champs [largeData1 ... n]. Toutefois, si un champ largeData est null, il doit traverser la hiérarchie jusqu'à ce qu'une valeur non nulle pour ce champ soit rencontrée. Il devrait, en bref, fonctionner comme la fonction coalesce, sauf à travers une hiérarchie de lignes au lieu d'un ensemble de colonnes.
Exemple:
où [id] = 1:
id: 1
parentID: null
largeData1: blah blah blah
largeData2: null
où [id] = 2
id: 1
parentID: 1
largeData1: blah blah blah
largeData2: null
où [id] = 3
id: 3
parentID: 1
largeData1: foo bar foobar
largeData2: null
Où [id] = 4
id: 4
parentID: 3
largeData1: foo bar foobar
largeData2: lorem ipsum
Où [id] = 5
id: 5
parentID: 4
largeData1: foo bar foobar
largeData2: lorem ipsum
Jusqu'à présent, j'ai ceci:
Declare @id Integer; Set @id = 5;
With heirarchy
(id, parentID, largeData1, largeData2, [level])
As (
Select id, parentID, largeData1,
largeData2, 1 As [level]
From example
Where id = @id
Union All
Select parent.id, parent.parentID,
parent.largeData1,
parent.largeData2,
child.[level] + 1 As [level]
From example As parent
Inner Join heirarchy As child
On parent.id = child.parentID)
Select id, parentID,
(Select top 1 largeData1
From heirarchy
Where largeData1 Is Not Null
Order By [level] Asc) As largeData1,
(Select top 1 largeData2
From heirarchy
Where largeData2 Is Not Null
Order By [level] Asc) As largeData2
From example
Where [id] = @id;
Cette renvoie les résultats que je recherche. Cependant, selon le plan de requête, il effectue un passage séparé à travers la hiérarchie pour chaque champ largeData que je recule.
Comment rendre cela plus efficace?
Ceci est évidemment une version simplifiée d'un problème plus complexe. La requête finale retournera les données au format XML, de sorte que toutes les solutions impliquant la clause FOR XML sont parfaitement bien.
Je peux créer une fonction d'agrégation CLR pour cela, si cela peut aider. Je n'ai pas encore exploré cette route.
+1 pour faire monter des valeurs non nulles. Mais l'utilisation de MAX peut être problématique. Si la ligne 3 de l'exemple de données indique "afoo bar bar" au lieu de "foo bar bar", la requête pour @ id = 5 retournera "bla bla bla" pour largeData1. – 8kb
Lorsque "remonter" dans le CTE, si à un niveau donné la valeur d'une colonne est nulle, elle est remplacée par la valeur à ce niveau, sinon elle est laissée inchangée. Une ligne est produite par niveau. Ainsi, lorsque le cte est terminé, la valeur d'une colonne sur toutes les lignes sera soit nulle soit la première valeur rencontrée. Les agrégations ignorent les valeurs nulles, laissant uniquement la valeur de max (ou min) à sélectionner. –