2010-03-09 12 views
7

que tengo una tabla como ésta (simplificado):generar estructurado de documentos (XML) a partir de datos de las tablas jerárquicas (T-SQL)

ID | Name | Parent 
--------------------------------- 
1 | IND | NULL 
2 | INS | 5 
3 | CON | NULL 
4 | AUT | 1 
5 | FIN | NULL 
6 | PHA | 1 
7 | CFIN | 5 
8 | CMRKT | 7 

DDL:

CREATE TABLE [dbo].[tblIndustryCodes](
     [IdIndustry] [int] IDENTITY(1,1) NOT NULL, 
     [IndustryCode] [nvarchar](5) NULL, 
     [IndustryName] [nvarchar](50) NULL, 
     [ParentId] [int] NULL, 
CONSTRAINT [PK_tblIndustryCodes] PRIMARY KEY CLUSTERED (  [IdIndustry] ASC)) 

partes movibles:

INSERT INTO [tblIndustryCodes] 
      ([IndustryCode] 
      ,[IndustryName] 
      ,[ParentId]) 
    VALUES 
      ('IND','Industry',NULL), 
      ('PHARM','Pharmacy',1), 
      ('FIN','Finance',NULL), 
      ('CFIN','Corporate Finance',3), 
      ('CMRKT','Capital Markets',4) 

Y me gustaría generar un archivo xml a partir de él, que está estructurado de acuerdo con las ID padre

como esto (simplificado)

<IND> 
    <AUT> 
    <PHA> 
<CON> 
<FIN> 
    <CFIN> 
     <CMRKT> 

creo que es hecho un poco tal vez con un poco de recursividad o algo así, pero no sé cómo. ¡Cualquier ayuda es muy apreciada!

edición: Es un SQL Server Express 2008

Realmente no importa si es o no válida XML, porque yo sólo lo uso para rellenar un control TreeView.

edit2: Probablemente usaría "FOR XML EXPLICIT" pero realmente no entiendo la sintaxis cuando no hay una profundidad máxima fija del árbol.

Edit3: para facilitar la comprensión de la tarea, he añadido el DDL para la tabla

+0

lo quieres como tu ejemplo de salida o como XML real? también, ¿qué versión de la base de datos? –

+1

Edité la publicación original, gracias. –

+2

muy similar a este pedido hace un tiempo: http://stackoverflow.com/questions/2408459/t-sql-question-query-to-xml –

Respuesta

12

Sobre la base de la respuesta de Recep (ver comentarios) creé la siguiente solución para este problema:

1. Crear una función recursiva

CREATE function SelectChild(@key as int) 
returns xml 
begin 
    return (
     select 
      IdIndustry as "@key", 
      ParentId as "@parentkey", 
      IndustryCode as "@Code", 
      IndustryName as "@Name", 
      dbo.SelectChild(IdIndustry) 
     from tblIndustryCodes 
     where ParentId = @key 
     for xml path('record'), type 
    ) 
end 

2. Construir una instrucción SELECT, que llama a la función

SELECT 
    IdIndustry AS "@key", 
    '' AS "@parentkey", 
    IndustryCode as "@Code", 
    IndustryName as "@Name", 
    dbo.SelectChild(IdIndustry)  
FROM dbo.tblIndustryCodes 
WHERE ParentId is null 
FOR XML PATH ('record') 

Esto crea un XML jerárquico, sin importar la profundidad del árbol que realmente es:

<record key="1" parentkey="" Code="IND" Name="Industry"> 
    <record key="2" parentkey="1" Code="AUTO" Name="Automotive" /> 
    <record key="3" parentkey="1" Code="PHARM" Name="Pharmaceuticals" /> 
</record> 
<record key="4" parentkey="" Code="FIN" Name="Finance"> 
    <record key="5" parentkey="4" Code="CFIN" Name="Corporate Finance"> 
    <record key="6" parentkey="5" Code="CMRKT" Name="Capital Markets" /> 
    </record> 
</record> 
<record key="7" parentkey="" Code="CON" Name="Cosulting"> 
    <record key="8" parentkey="7" Code="IMPL" Name="Implementation" /> 
    <record key="9" parentkey="7" Code="STRAT" Name="Strategy" /> 
</record> 
2

También puede hacer esto sin crear una función separada, mediante la inclusión de la sub-consulta como una columna adicional que devuelve XML. Por ejemplo, la siguiente devolverá un documento XML que contiene jerárquica usuarios y su lista de asociados de los roles:

SELECT 
    FirstName, LastName, 
    CONVERT(XML, 
     (SELECT r.UserID, r.RoleID 
     FROM global.[UserRole] r 
     WHERE r.USerID = [user].UserID 
     FOR XML RAW ('Role'), ELEMENTS, root('Roles') 
    )) 
FROM global.[user] 
FOR XML RAW ('User'), ELEMENTS, root('Users') 
+0

Dave: ¿Esto realmente devolvería la profundidad total del árbol? –

+0

@Dave ¡Este es el mejor, flexible pero muy corto! – Jeb50

+0

@AndreasJansson Sí. ¡Solo intenté usar datos de la vida real, funciona! Para verificarlo rápido, puede agregar los 5 mejores en el SELECT más externo. – Jeb50

Cuestiones relacionadas