动态table显示

Dynamic table display

我们的来源 table 来自其他用户,每次都有不同的列数。例如,今天 table 显示为:

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

但明天是:

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

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

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 可能会解决这个问题,但如何解决?

看起来很适合动态 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. 从输入的元数据中获取列列表 table 并将它们连接起来 [eye],[tail],[skin]

  2. 准备带有列占位符的主查询

  3. 用实际列名替换占位符

  4. 执行dynamic-SQL

  5. 勾选EAVtable