将数据从2个表转换为1个

时间:2017-03-04 11:59:03

标签: sql sql-server

我正在使用一个数据库,该数据库允许在“Item”表中存储“Custom Property”字段和每条记录。这是通过在Item表中通过[CustomString199],[CustomNumber00]到[CustomNumber199]和[CustomDate00]到[CustomDate00]通过[CustomString00]调用预设字段来完成的。还有另一个名为“CustomProperty”表的表,它将名称分配给每个自定义字段以及要在Item表中使用的列。这是它的外观。

Item:
| Id | CustomString00| ... | CustomString199 | CustomNumber00 | ... | CustomNumber199 | CustomDate00 | ... | CustomDate199 |
| 1  | 'IN REPAIR'   | ... | NULL            | 78.4           | ... | NULL            | 2017-03-04   | ... | NULL          |
| 2  | 'FINISHED'    | ... | NULL            | 68.5           | ... | NULL            | 2017-03-05   | ... | NULL          |
| 3  | 'WIP'         | ... | NULL            | NULL           | ... | NULL            | 2017-03-07   | ... | NULL          |

CustomProperty:
| Name          | Type| ColumnName       |
| 'Status'      | 0   | 'CustomString00' |
| 'Temperature' | 1   | 'CustomNumber00' |
| 'Made Date'   | 2   | 'CustomDate00'   |

对于定义的每个自定义属性,CustomProperty表中将有一条记录,它将指示它是什么数据类型以及该属性使用哪个列。目前,每种类型最多可定义200个自定义属性,即200 Text,200 Date和200 Numeric。用户根据需要定义自定义属性。如果用户仅使用55个自定义属性,则不会使用Item表中的许多字段。

我想创建一个更“友好”的视图,以便我们的用户可以创建自己的报告来显示这些属性。此视图将使用这两个表来创建一个如下所示的新表:

| Id | Status      | Temperature | Made Date  |
| 1  | 'IN REPAIR' | 78.4        | 2017-03-04 |
| 2  | 'FINISHED'  | 68.5        | 2017-03-05 |
| 3  | 'WIP'       | NULL        | 2017-03-07 |

此视图应显示Custom Property表中定义的每个属性的列。对于此示例,仅定义了3个自定义属性,因此在此视图中显示3个字段。如果定义了所有600个自定义属性,则此视图中将有600个字段。如果在Item表中为该Custom属性存储了值,则会显示该值。如果没有值,那么将为该属性显示NULL(如第3项的温度所示)。

使用动态SQL我有一些结果,但不是我想要的。我做了一个查询,取消隐藏自定义属性字段并返回像这样的项的结果:

| Id | CPName        | CPTextValue | CPNumberValue | CPDateValue |
| 1  | 'Status'      | 'IN REPAIR' | NULL          | NULL        |
| 1  | 'Temperature' | NULL        | 78.4          | NULL        |
| 1  | 'Made Date'   | NULL        | NULL          | 2017-03-04  |
| 2  | 'Status'      | 'FINISHED ' | NULL          | NULL        |
| 2  | 'Temperature' | NULL        | 68.5          | NULL        |
| 2  | 'Made Date'   | NULL        | NULL          | 2017-03-05  |
| 3  | 'Status'      | 'WIP'       | NULL          | NULL        |
| 3  | 'Made Date'   | NULL        | NULL          | 2017-03-07  |

我的查询变得非常复杂,所以我想知道我是否采取了错误的方法。这是我到目前为止所做的。

DECLARE @textcolsUnpivot AS NVARCHAR(MAX),
        @datecolsUnpivot AS NVARCHAR(MAX),
        @numbercolsUnpivot AS NVARCHAR(MAX),
        @query AS NVARCHAR(MAX)

select @textcolsUnpivot 
      = stuff((select ','+quotename(columnname)
        from customproperty
        where custompropertytype = 0
    order by columnname
    for xml path('')), 1, 1, '')

select @datecolsUnpivot 
  = stuff((select ','+quotename(columnname)
    from customproperty
    where custompropertytype = 1
    order by columnname
    for xml path('')), 1, 1, '')

select @numbercolsUnpivot 
  = stuff((select ','+quotename(columnname)
    from customproperty
    where custompropertytype = 2
    order by columnname
    for xml path('')), 1, 1, '')

set @query 
  = 'select id, CPName, CPTextValue, NULL as CPDateValue, NULL as CPNumberValue from 
        (select id, CPTextValue, CPCol from item
            unpivot
            (
                CPTextValue
                for CPCol in ('+ @textcolsunpivot +')
            ) unpiv ) as pv
    inner join
        (select columnname, name as CPName, custompropertytype from customproperty) as cp
        on cp.columnname = pv.CPCol
    union
    select id, CPName, NULL, CPDateValue, NULL from 
        (select id, CPDateValue, CPCol from item
            unpivot
            (
                CPDateValue
                for CPCol in ('+ @datecolsunpivot +')
            ) unpiv ) as pv
    inner join
        (select columnname, name as CPName, custompropertytype from customproperty) as cp
        on cp.columnname = pv.CPCol
    union
    select id, CPName, NULL, NULL, CPNumberValue from 
        (select id, CPNumberValue, CPCol from item
            unpivot
            (
                CPNumberValue
                for CPCol in ('+ @numbercolsunpivot +')
            ) unpiv ) as pv
    inner join
        (select columnname, name as CPName, custompropertytype from customproperty) as cp
        on cp.columnname = pv.CPCol
    '

exec sp_executesql @query;

有关其他说明,表格的架构为:

Item:
Id - pk, (it's actually a GUID, but I'm using an int for this example.), not null
CustomString00 through CustomString199 - nvarchar(max), null
CustomDate00 through CustomDate199 - datetime, null
CustomNumber00 through CustomNumber199 - float, null

CustomProperty:
Name - nvarchar(100),not null
Type - int, not null
ColumnName - nvarchar(50), not null

如果我要继续我当前的方法,我想我现在需要将我之前查询的结果PIVOT,以便将其置于我正在寻找的形式中。这是对的吗?

0 个答案:

没有答案