tengo una tabla que define una jerarquía:de consultas SQL: jerárquica 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;
diagrama de jerarquía para estos datos:
Quiero escribir una consulta que devolverá un único fila para cualquier valor [id] dado. La fila debe contener la información de esa fila [id] y [parentID]. También debe contener los campos [largeData1 ... n]. Sin embargo, si un campo largeData es nulo, debe recorrer la jerarquía hasta que se encuentre un valor no nulo para ese campo. En resumen, debe funcionar como la función de fusión, excepto a través de una jerarquía de filas en lugar de un conjunto de columnas.
Ejemplo:
Donde [id] = 1:
id: 1
parentID: null
largeData1: blah blah blah
largeData2: null
Donde [id] = 2
id: 1
parentID: 1
largeData1: blah blah blah
largeData2: null
Donde [id] = 3
id: 3
parentID: 1
largeData1: foo bar foobar
largeData2: null
Donde [id] = 4
id: 4
parentID: 3
largeData1: foo bar foobar
largeData2: lorem ipsum
Donde [id] = 5
id: 5
parentID: 4
largeData1: foo bar foobar
largeData2: lorem ipsum
Hasta ahora, tengo esto:
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;
Este devuelve los resultados que estoy buscando. Sin embargo, de acuerdo con el plan de consulta, está haciendo un pase separado a través de la jerarquía para cada campo de datos grandes que retiro.
¿Cómo puedo hacer esto más eficiente?
Esta es obviamente una versión simplificada de un problema más complejo. La consulta final devolverá los datos en formato XML, por lo que cualquier solución que implique la cláusula FOR XML está perfectamente bien.
Puedo crear una función de agregado CLR para esto, si hacerlo ayudaría. Aún no exploré esa ruta.
+1 para aumentar los valores no nulos. Pero usar MAX puede ser problemático. Si la fila 3 de los datos de muestra dice "afoo bar bar" en lugar de "foo bar bar", la consulta para @ id = 5 devolverá "blah blah blah" para largeData1. – 8kb
Cuando "sube" dentro del CTE, si en un nivel determinado el valor de una columna es nulo, se reemplaza con el valor en ese nivel; de lo contrario, no se modifica. Se produce una fila por nivel. Por lo tanto, cuando se completa el cte, el valor de una columna en todas las filas será nulo o el primer valor encontrado. Las agregaciones ignoran los valores nulos, dejando solo un valor para max (o min) para seleccionar. –