2010-09-22 5 views
6

Estoy tratando de transformar una tabla en una estructura XML y quiero que una de las columnas en mi tabla represente un nodo principal y la otra columna represente un nodo secundario.Transformar la tabla SQL en XML con la columna como nodo principal

Tengo parte del camino, pero no tengo la solución completa. Necesito que la columna TABLE_NAME se transforme en un nodo padre xml y la columna COLUMN_NAME para transformarlos en nodos secundarios. Si ejecuto lo siguiente obtengo el anidamiento pero también obtengo varios nodos principales.

select 
TABLE_NAME AS 'tn', 
COLUMN_NAME AS 'tn/cn' 
from (
select 'TABLE_A' AS TABLE_NAME, 'COLUMN_1' AS COLUMN_NAME 
UNION ALL 
select 'TABLE_A' AS TABLE_NAME, 'COLUMN_2' AS COLUMN_NAME 
UNION ALL 
select 'TABLE_B' AS TABLE_NAME, 'COLUMN_1' AS COLUMN_NAME 
UNION ALL 
select 'TABLE_B' AS TABLE_NAME, 'COLUMN_2' AS COLUMN_NAME 
) x 
for xml path(''), ROOT('datatable') 

OUPUT >>>

<datatable> 
    <tn>TABLE_A<cn>COLUMN_1</cn></tn> 
    <tn>TABLE_A<cn>COLUMN_2</cn></tn> 
    <tn>TABLE_B<cn>COLUMN_1</cn></tn> 
    <tn>TABLE_B<cn>COLUMN_2</cn></tn> 
</datatable> 

salida deseada >>>

<datatable> 
    <TABLE_A> 
    <cn>COLUMN_1</cn> 
    <cn>COLUMN_2</cn> 
    </TABLE_A> 
    <TABLE_B> 
    <cn>COLUMN_1</cn> 
    <cn>COLUMN_2</cn> 
    </TABLE_B> 
</datatable> 

Es esto posible o estoy soñando? y es posible sin XML EXPLICIT o es este el tipo de cosas EXPLICIT que hay para?

La otra posibilidad que he estado intentando es rellenar el xml y luego aplicar una xquery, pero aún no me alegro con eso.

Gracias,

Gary

+0

@Gary, que dialecto de SQL (Ora cle, SQLServer, MySQL, etc.) ¿estás usando? Algunos de ellos tienen extensiones dialecto-específicas para manejar XML. –

+0

Hola Mark, estoy usando el M $ SQL Server 2008 R2, edición estándar –

+2

¿Ha considerado exportar a XML y luego ejecutar una transformación XSL en él? –

Respuesta

3

Como han mencionado otros, FOR XML no le permite nombrar dinámicamente nodos. Los nombres de nodo deben ser constantes para cuando se compila la consulta en sí. Puede solucionar esto con sql dinámico pero luego termina con un código que se vuelve más y más difícil de leer.

Una alternativa sería la de generar manualmente los nodos de nombre talbe y echado en XML:

Configuración:

CREATE TABLE a (table_name VARCHAR(20), column_name VARCHAR(20) 
INSERT INTO a VALUES ('TABLE_A', 'COLUMN_1') 
INSERT INTO a VALUES ('TABLE_A', 'COLUMN_2') 
INSERT INTO a VALUES ('TABLE_B', 'COLUMN_1') 
INSERT INTO a VALUES ('TABLE_B', 'COLUMN_2') 

ejecutar:

SELECT CAST(
     '<' + table_name + '>' 
    + (SELECT c.column_name as 'CN' 
     FROM a c 
     WHERE c.table_name = p.table_name 
     FOR XML PATH('')) 
    + '</' + table_name + '>' 
    AS XML) 
    FROM a p 
GROUP BY p.table_name 
FOR XML PATH(''), ROOT('datatable') 

Produce:

<datatable> 
    <TABLE_A> 
    <CN>COLUMN_1</CN> 
    <CN>COLUMN_2</CN> 
    </TABLE_A> 
    <TABLE_B> 
    <CN>COLUMN_1</CN> 
    <CN>COLUMN_2</CN> 
    </TABLE_B> 
</datatable> 
2

Es posible, es necesario nombrar columnas con el camino. De esta manera: 'parent\child'.

Prueba esto:

select 
( 
select * from (
    select 'COLUMN_1' 'cn' 
    UNION ALL 
    select 'COLUMN_2' 'cn' 
) as t 
for xml path(''), root('TABLE_A'), type 
) 
,( 
select * from (
    select 'COLUMN_1' 'cn' 
    UNION ALL 
    select 'COLUMN_2' 'cn' 
) as t 
for xml path(''), root('TABLE_B'), type 
) 
for xml path(''), ROOT('datatable') 
+0

Lo siento, necesito una solución de producción que funcione en grandes entradas de tabla sin la necesidad de codificar cosas como root ('TABLE_A'). –

+0

Cuanto más lo pienso, más pienso que no se puede hacer. Estoy pidiendo los datos en mi primera columna para representar los nombres de los nodos y los datos en mi segunda columna para representar los valores de los nodos. –

+0

@ sqlconsumer.net puedes construir cualquier tipo de xml como varchar y luego convertirlo como xml –

3

desgracia - lo que usted está tratando de hacer no es posible. Dos problemas importantes (si tiene margen de maniobra, puede haber una solución).

En primer lugar, NINGUNA de las opciones de XML en SQL (ni siquiera utilizando EXPLICIT) permite la nomenclatura dinámica de nodos. Puede usar un atributo <tn id="TABLE_A" /> o un valor <tn>TABLE_A</tn> pero no puede obtener <TABLE_A> a menos que lo codifique.

Los tipos XML permiten anidar/subconsultas.

SELECT V1.tbname 
,(SELECT V2.colname FROM testtable V2 
    WHERE V1.tbname = V2.tbname FOR XML PATH(''), ELEMENTS, TYPE) 
FROM testtable V1 
FOR XML AUTO, ROOT('datatable') 

Su segundo problema proviene del hecho de que sus datos están desnormalizados. No hay forma de obtener una lista única de tablas (no se puede usar DISTINCT en lo anterior porque SQL no puede comparar tipos XML). Esto limita lo que puede hacer en un solo "pase" (declaración).

Si está dispuesto a usar una tabla temporal (o variable de tabla) puede seleccionar una lista distinta de nombres de tabla y luego unirla con los nombres de columna como en el ejemplo dado (ejecute primero lo siguiente y reemplace el externo de @tblist).

DECLARE @tblist TABLE (tbname varchar(20)) 
INSERT INTO @tblist SELECT DISTINCT tbname FROM testtable 

Devuelve esto:

<datatable> 
    <V1 tbname="TBA"> 
    <colname>COL 1</colname> 
    <colname>COL 2</colname> 
    </V1> 
    <V1 tbname="TBB"> 
    <colname>COL 1</colname> 
    <colname>COL 2</colname> 
    </V1> 
</datatable> 

Usted también tiene que estar dispuesto a tener su nombre nodos de tabla sean atributos (siempre se puede ejecutar un GREP o simplemente reemplazar después de hacer el nodo se valorarán) estaría cerca si no exactamente el formato que está buscando.

Lo siento, probablemente no es lo que quiere escuchar. Pero en un par de pasos simples se puede hacer. Simplemente no directamente de SQL Server en una sola declaración.

Cuestiones relacionadas