动态表格显示

时间:2015-12-31 08:04:22

标签: sql sql-server tsql entity-attribute-value unpivot

我们的其他用户的源表每次都有不同的列数。例如,今天的表格如下:

Name   Eye   tail
-------------------
Dog     Blue  long
Cat     Red   short

但明天是:

Name   eye   tail skin
-------------------
Dog    blue  long  white
Lion   green short  brown

我们的目标是将数据传输到这样一个固定的模式表中:

name   property    value
-------------------------
Dog    Eye         blue
Dog    tail        long
Dog    skin        white
Lion   Eye         green
Lion   Tail        short
Lion   skin        brown  

为实现这一目标,现在我们使用半手动修改的存储过程进行此类转换:

SELECT * 
INTO #T 
FROM table.original

INSERT INTO table.target(name, property, value)
    SELECT name, property, value 
    FROM
        --below is manually modified each time
        (SELECT name = a.name, property = 'eye', value = a.eye 
         FROM #T a
         UNION ALL
         SELECT name, 'tail', tail 
         FROM #T
         UNION ALL
         SELECT name, 'skin', skin 
         FROM #T
         UNION ALL
         .........
       )

有没有办法自动进行此类转换?我认为FOR XML可以解决这个问题,但是如何解决?

1 个答案:

答案 0 :(得分:2)

看起来非常适合动态UNPIVOT

DECLARE @columns NVARCHAR(MAX);

SELECT @columns = STUFF ((SELECT ',' + QUOTENAME(COLUMN_NAME)
                          FROM INFORMATION_SCHEMA.COLUMNS
                          WHERE [table_name] = 'tab'
                            AND column_name <> 'Name'
                          FOR XML PATH ('')),1,1,'');

DECLARE @sql NVARCHAR(MAX) = 
N'INSERT INTO target(name, property, [value])
SELECT Name, property, [value]
FROM tab t
UNPIVOT
(
  [value] FOR property IN (<placeholder>)
) unpvt;';

SET @sql = REPLACE(@sql, '<placeholder>', @columns);  

EXEC dbo.sp_executesql
       @sql;

SELECT *
FROM target;

SqlFiddleDemo SqlFiddleDemo2

输出:

╔═══════╦═══════════╦═══════╗
║ name  ║ property  ║ value ║
╠═══════╬═══════════╬═══════╣
║ Dog   ║ eye       ║ blue  ║
║ Dog   ║ tail      ║ long  ║
║ Dog   ║ skin      ║ white ║
║ Lion  ║ eye       ║ green ║
║ Lion  ║ tail      ║ short ║
║ Lion  ║ skin      ║ brown ║
╚═══════╩═══════════╩═══════╝

工作原理:

  1. 从输入表的元数据中获取列列表并将它们连接起来[eye],[tail],[skin]

  2. 使用占位符为列

  3. 准备主查询
  4. 将占位符替换为实际列名

  5. 执行dynamic-SQL

  6. 检查EAV