Sql 具有动态字段类型的服务器动态数据透视表
Sql server dynamic pivot with dynamic fields type
我需要在 Sql Server 2005 上构建一个动态枢轴 table,我找到了几个关于如何做的很好的答案,但我有一个额外的要求来实现:动态字段类型.
这是我的数据结构
CREATE TABLE [dbo].[MyData](
[Key] [char](12) NOT NULL,
[AttributeName] [char](3) NOT NULL,
[AttributeValue] [char](40) NOT NULL)
这是类型的定义。
CREATE TABLE [dbo].[Attributes](
[AttributeName] [char](3) NOT NULL,
[CastTo] [char](10) NOT NULL,
[Size] int NULL,
[Precision] int NULL)
这是预期的结果:
KEY | 001 (of type found in tab Attributes) | 002 | 003 |004 |...
---------------------------------------------------------------------------------------
k1 | I am a Varchar | 12345.789 | 0 (bit)| 2014-10-02 |...
MyData 可以包含大约 100.000 个不同的键和大约 500 个不同的 AttributeName。
这是一些示例数据:
INSERT [MyAttributes] ([AttributeName], [CastTo], [Size], [Precision]) VALUES (N'001', N'varchar , 10, NULL)
GO
INSERT [MyAttributes] ([AttributeName], [CastTo], [Size], [Precision]) VALUES (N'002', N'int ', NULL, NULL)
GO
INSERT [MyAttributes] ([AttributeName], [CastTo], [Size], [Precision]) VALUES (N'003', N'datetime ', NULL, NULL)
GO
INSERT [MyAttributes] ([AttributeName], [CastTo], [Size], [Precision]) VALUES (N'004', N'decimal ', 10, 4)
GO
INSERT [MyData] ([Key], [AttributeName], [AttributeValue]) VALUES (N'k1', N'001', N'abcd ')
GO
INSERT [MyData] ([Key], [AttributeName], [AttributeValue]) VALUES (N'k1', N'002', N'111 ')
GO
INSERT [MyData] ([Key], [AttributeName], [AttributeValue]) VALUES (N'k1', N'003', N'20150102 ')
GO
INSERT [MyData] ([Key], [AttributeName], [AttributeValue]) VALUES (N'k1', N'004', N'12345.1 ')
GO
INSERT [MyData] ([Key], [AttributeName], [AttributeValue]) VALUES (N'k2', N'001', N'efgh ')
GO
INSERT [MyData] ([Key], [AttributeName], [AttributeValue]) VALUES (N'k2', N'002', N'222 ')
GO
INSERT [MyData] ([Key], [AttributeName], [AttributeValue]) VALUES (N'k3', N'003', N'20121212 ')
GO
对于 table MyData 中的每个不同的 Key,我必须创建一个以 Key 作为第一个字段的记录,然后对于每个不同的 AttributeName,我必须在 Attributes table 上查找正确的类型、大小和精度,输出一个名为 [AttributeName] 的正确类型的字段,并将 cast [AttributeValue] 转换为正确的类型 .
这可以使用 Pivot 完成吗?或者 FOR XML 子句的一些技巧可能有助于考虑字段类型?除了自定义存储过程之外,我不知道生成大量动态 sql 但它不容易回收,可能难以维护且效率低下。
我找到了这个可行的解决方案。
它不完整(缺少 varchar 的大小和数字类型的精度)但足以理解这个想法。
转换不能在数据透视部分完成,当然在查询源 table 时也不能工作,因为类型是混合的。
我找到的解决方案是将强制转换添加到动态列列表中,为数据透视表创建一个更简单的列表(仅字段名称),为主 select.
创建一个更长的列表(包括强制转换)
DECLARE @columns NVARCHAR(MAX), @sql NVARCHAR(MAX), @ColumnsShort nVarChar(MAX);
SET @columnsShort = '';
SELECT @columnsShort = @columnsShort + N', p.' + QUOTENAME(AttributeName)
FROM (SELECT distinct p.AttributeName FROM MyData AS p
INNER JOIN MyAttributes AS o
ON rtrim(p.AttributeName) = rtrim(o.AttributeName)
) AS x;
SET @columns = '';
SELECT @columns = @columns + N', ' + attr
FROM (SELECT distinct 'CAST(' + QUOTENAME(p.AttributeName) + ' AS ' + o.CastTo + ') AS ' + QUOTENAME(p.attributename) as attr FROM MyData AS p
INNER JOIN MyAttributes AS o
ON rtrim(p.AttributeName) = rtrim(o.AttributeName)
) AS x;
SET @sql = N'
SELECT [Key], ' + STUFF(@columns, 1, 2, '') + '
FROM
(
SELECT [key], p.AttributeName, attributevalue
FROM dbo.MyData AS p
INNER JOIN dbo.MyAttributes AS o
ON rtrim(p.AttributeName) = rtrim(o.AttributeName)
) AS j
PIVOT
(
max(AttributeValue) FOR AttributeName IN ('
+ STUFF(REPLACE(@columnsshort, ', p.[', ',['), 1, 1, '')
+ ')
) AS p;';
PRINT @sql;
execute sp_executesql @sql
我需要在 Sql Server 2005 上构建一个动态枢轴 table,我找到了几个关于如何做的很好的答案,但我有一个额外的要求来实现:动态字段类型.
这是我的数据结构
CREATE TABLE [dbo].[MyData](
[Key] [char](12) NOT NULL,
[AttributeName] [char](3) NOT NULL,
[AttributeValue] [char](40) NOT NULL)
这是类型的定义。
CREATE TABLE [dbo].[Attributes](
[AttributeName] [char](3) NOT NULL,
[CastTo] [char](10) NOT NULL,
[Size] int NULL,
[Precision] int NULL)
这是预期的结果:
KEY | 001 (of type found in tab Attributes) | 002 | 003 |004 |...
---------------------------------------------------------------------------------------
k1 | I am a Varchar | 12345.789 | 0 (bit)| 2014-10-02 |...
MyData 可以包含大约 100.000 个不同的键和大约 500 个不同的 AttributeName。
这是一些示例数据:
INSERT [MyAttributes] ([AttributeName], [CastTo], [Size], [Precision]) VALUES (N'001', N'varchar , 10, NULL)
GO
INSERT [MyAttributes] ([AttributeName], [CastTo], [Size], [Precision]) VALUES (N'002', N'int ', NULL, NULL)
GO
INSERT [MyAttributes] ([AttributeName], [CastTo], [Size], [Precision]) VALUES (N'003', N'datetime ', NULL, NULL)
GO
INSERT [MyAttributes] ([AttributeName], [CastTo], [Size], [Precision]) VALUES (N'004', N'decimal ', 10, 4)
GO
INSERT [MyData] ([Key], [AttributeName], [AttributeValue]) VALUES (N'k1', N'001', N'abcd ')
GO
INSERT [MyData] ([Key], [AttributeName], [AttributeValue]) VALUES (N'k1', N'002', N'111 ')
GO
INSERT [MyData] ([Key], [AttributeName], [AttributeValue]) VALUES (N'k1', N'003', N'20150102 ')
GO
INSERT [MyData] ([Key], [AttributeName], [AttributeValue]) VALUES (N'k1', N'004', N'12345.1 ')
GO
INSERT [MyData] ([Key], [AttributeName], [AttributeValue]) VALUES (N'k2', N'001', N'efgh ')
GO
INSERT [MyData] ([Key], [AttributeName], [AttributeValue]) VALUES (N'k2', N'002', N'222 ')
GO
INSERT [MyData] ([Key], [AttributeName], [AttributeValue]) VALUES (N'k3', N'003', N'20121212 ')
GO
对于 table MyData 中的每个不同的 Key,我必须创建一个以 Key 作为第一个字段的记录,然后对于每个不同的 AttributeName,我必须在 Attributes table 上查找正确的类型、大小和精度,输出一个名为 [AttributeName] 的正确类型的字段,并将 cast [AttributeValue] 转换为正确的类型 .
这可以使用 Pivot 完成吗?或者 FOR XML 子句的一些技巧可能有助于考虑字段类型?除了自定义存储过程之外,我不知道生成大量动态 sql 但它不容易回收,可能难以维护且效率低下。
我找到了这个可行的解决方案。
它不完整(缺少 varchar 的大小和数字类型的精度)但足以理解这个想法。 转换不能在数据透视部分完成,当然在查询源 table 时也不能工作,因为类型是混合的。 我找到的解决方案是将强制转换添加到动态列列表中,为数据透视表创建一个更简单的列表(仅字段名称),为主 select.
创建一个更长的列表(包括强制转换)DECLARE @columns NVARCHAR(MAX), @sql NVARCHAR(MAX), @ColumnsShort nVarChar(MAX);
SET @columnsShort = '';
SELECT @columnsShort = @columnsShort + N', p.' + QUOTENAME(AttributeName)
FROM (SELECT distinct p.AttributeName FROM MyData AS p
INNER JOIN MyAttributes AS o
ON rtrim(p.AttributeName) = rtrim(o.AttributeName)
) AS x;
SET @columns = '';
SELECT @columns = @columns + N', ' + attr
FROM (SELECT distinct 'CAST(' + QUOTENAME(p.AttributeName) + ' AS ' + o.CastTo + ') AS ' + QUOTENAME(p.attributename) as attr FROM MyData AS p
INNER JOIN MyAttributes AS o
ON rtrim(p.AttributeName) = rtrim(o.AttributeName)
) AS x;
SET @sql = N'
SELECT [Key], ' + STUFF(@columns, 1, 2, '') + '
FROM
(
SELECT [key], p.AttributeName, attributevalue
FROM dbo.MyData AS p
INNER JOIN dbo.MyAttributes AS o
ON rtrim(p.AttributeName) = rtrim(o.AttributeName)
) AS j
PIVOT
(
max(AttributeValue) FOR AttributeName IN ('
+ STUFF(REPLACE(@columnsshort, ', p.[', ',['), 1, 1, '')
+ ')
) AS p;';
PRINT @sql;
execute sp_executesql @sql