简体   繁体   English

SQL Server:从链接到另一个表的ID列动态创建列

[英]SQL Server : dynamically create columns from an ID column linking to another table

I'm trying to dynamically create columns based on an ID that links to another table for column names. 我正在尝试根据链接到另一个表的列名的ID动态创建列。 (I have no idea if this is even possible it will be used for ssrs reports and gridviews on a webpage.) (我不知道是否有可能将其用于网页上的ssrs报告和gridview。)

Take a look at the example below - the "Current table" is how it looks now. 看一下下面的示例-“当前表”就是现在的样子。 I have a column for every name. 我为每个名字都有一栏。 I already have the definition table created. 我已经创建了定义表。 I want to make the current table look like the proposed table and "CREATE" the columns in a select or something using the definition table for names to look like it does now. 我想使当前表看起来像拟议的表,并在选择表或使用定义表的名称中“创建”列,使其名称看起来像现在一样。

在此处输入图片说明

Here is one approach that will "dynamically" unpivot your data without actually using dynamic SQL. 这是一种无需实际使用动态SQL即可“动态”取消数据透视的方法。

Clearly Gordon's would be more performant, but here, you don't have to declare the columns. 显然,戈登的性能更高,但是在这里,您不必声明这些列。

Example

Select  D.id
       ,[count] = C.Value
       ,A.ts
 From  CurrentTable A
 Cross Apply ( values (cast((Select A.* for XML RAW) as xml))) B(XMLData)
 Cross Apply (
                Select Item = a.value('local-name(.)','varchar(100)')
                      ,Value = a.value('.','int')    -- Use appropriate type
                 From  B.XMLData.nodes('/row')  as C1(n)
                 Cross Apply C1.n.nodes('./@*') as C2(a)
                 Where a.value('local-name(.)','varchar(100)') not in ('ts','OtherColToExclude')
             ) C
 Join   definition D on C.item=D.Name

Returns 返回

id  count   ts
1   5       2018-12-06
2   88      2018-11-01
2   18      2018-10-18
3   32      2018-10-27
4   6       2018-10-27

This is a very strange data structure. 这是一个非常奇怪的数据结构。 Here is one method: 这是一种方法:

select d.id as definition,
       coalesce(c.p1, c.p2, c.p3, c.p4) as "count",
       c.ts
from current_table c join
     definition d
     on (d.name = 'p1' and p1 is not null) or
        (d.name = 'p2' and p2 is not null) or
        (d.name = 'p3' and p3 is not null) or
        (d.name = 'p4' and p4 is not null) ;

Also you can try to use unpivot to achieve your requirement. 您也可以尝试使用unpivot来满足您的要求。 For more details, you can refer to this article: https://docs.microsoft.com/en-us/sql/t-sql/queries/from-using-pivot-and-unpivot?view=sql-server-2017 有关更多详细信息,请参阅本文: https : //docs.microsoft.com/zh-cn/sql/t-sql/queries/from-using-pivot-and-unpivot?view=sql-server-2017

----drop table [current_table] 
----drop table [definition] 
create table [current_table] 
(p1 int,
p2 int,
p3 int,
p4 int,
ts date )
insert into [current_table] values
(5,null,null,null,'20181206'),
(null,88,null,null,'20181101'),
(null,18,null,null,'20181018'),
(null,null,32,null,'20181027'),
(null,null,null,6,'20181014')

create table [definition] 
(id int,
name varchar(5) )
insert into [definition] values 
(1,'p1'),(2,'p2'),
(3,'p3'),(4,'p4')

;with cte as (
SELECT [name] ,[count],ts 
FROM [current_table]  t
UNPIVOT ([count] FOR [name] IN ([p1],[p2],[p3],[p4])) u)
select b.id,a.count,a.ts from  cte a  join [definition] b on a.name=b.name
/*
id          count       ts
----------- ----------- ----------
1           5           2018-12-06
2           88          2018-11-01
2           18          2018-10-18
3           32          2018-10-27
4           6           2018-10-14
*/


------dynamic-------------
DECLARE @ColNames varchar(1000);
SET @ColNames = '';
SELECT @ColNames =stuff((
    SELECT DISTINCT ',' + QUOTENAME(COLUMN_NAME)
    FROM INFORMATION_SCHEMA.COLUMNS p2
    WHERE TABLE_NAME = 'current_table'
      AND COLUMN_NAME like 'p%'
    FOR XML PATH(''), TYPE).value('.', 'varchar(max)')
            ,1,1,'')
DECLARE @CMD nvarchar(2000);
SET @CMD = ';with cte as (
SELECT [name] ,[count],ts 
FROM [current_table]  t
UNPIVOT ([count] FOR [name] IN ('+@ColNames+')) u)
select b.id,a.count,a.ts from  cte a  join [definition] b on a.name=b.name'
PRINT @CMD
execute sp_executesql @CMD
/*
;with cte as (
SELECT [name] ,[count],ts 
FROM [current_table]  t
UNPIVOT ([count] FOR [name] IN ([p1],[p2],[p3],[p4])) u)
select b.id,a.count,a.ts from  cte a  join [definition] b on a.name=b.name
id          count       ts
----------- ----------- ----------
1           5           2018-12-06
2           88          2018-11-01
2           18          2018-10-18
3           32          2018-10-27
4           6           2018-10-14
*/

Hope it can help you. 希望它能对您有所帮助。

Best Regards, 最好的祝福,

Rachel 雷切尔

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM