Sql server 动态SQL中的动态转换
我正在尝试创建一个存储过程,该过程将返回一个结果集,该结果集的列数(在tblHeaderDefinition中定义)可变(也在tblHeaderDefinition中定义)。这些列的值作为VARCHAR存储在单独的表中,该表与定义表内部联接 一些不同的应用程序(在C#、VBA等中)引入此数据并以不同的方式使用它,但是当我引入此表时,我的列都是VARCHAR类型,与value列相同。我希望在SQL中将它们转换为适当的类型,并让应用程序查看列的type属性以确定如何处理列,而不是将定义表引入到每个应用程序中,并将每个应用程序转换为正确的类型 下面的查询返回我正在寻找的平面表,但是我想不出在这个实例中使用动态转换的方法Sql server 动态SQL中的动态转换,sql-server,casting,dynamic-sql,Sql Server,Casting,Dynamic Sql,我正在尝试创建一个存储过程,该过程将返回一个结果集,该结果集的列数(在tblHeaderDefinition中定义)可变(也在tblHeaderDefinition中定义)。这些列的值作为VARCHAR存储在单独的表中,该表与定义表内部联接 一些不同的应用程序(在C#、VBA等中)引入此数据并以不同的方式使用它,但是当我引入此表时,我的列都是VARCHAR类型,与value列相同。我希望在SQL中将它们转换为适当的类型,并让应用程序查看列的type属性以确定如何处理列,而不是将定义表引入到每个应
DECLARE @collist NVARCHAR(MAX)
SET @collist = stuff((SELECT DISTINCT ',' + QUOTENAME(ColumnName)
FROM tblHeaderDefinition
FOR XML PATH(''), TYPE
).value('.', 'NVARCHAR(MAX)')
,1,1,'')
DECLARE @q NVARCHAR(MAX)
SET @q = '
SELECT *
FROM (
SELECT ColumnName, Value
FROM (
SELECT tblHeaderDefinition.pkHeaderDefinitionID
, tblHeaderDefinition.ColumnName
, tblHeaderDefinition.ColumnType
, tblHeaderValue.Value
FROM tblHeaderValue
INNER JOIN tblHeaderDefinition ON tblHeaderValue.fkHeaderDefinitionID = tblHeaderDefinition.pkHeaderDefinitionID
) AS x
) AS source
pivot (
max(Value)
FOR ColumnName IN (' + @collist + ')
) AS pvt
'
EXEC (@q)
试验
我正在使用的表:
CREATE TABLE [dbo].[tblHeaderDefinition](
[pkHeaderDefinitionID] [int] IDENTITY(1,1) NOT NULL,
[ColumnName] [varchar](256) NULL,
[ColumnType] [varchar](256) NULL
) ON [PRIMARY]
GO
CREATE TABLE [dbo].[tblHeaderValue](
[pkHeaderValueID] [int] IDENTITY(1,1) NOT NULL,
[fkHeaderDefinitionID] [int] NULL,
[fkHeaderID] [int] NULL,
[Value] [varchar](256) NULL
) ON [PRIMARY]
GO
SET IDENTITY_INSERT [dbo].[tblHeaderDefinition] ON
GO
INSERT [dbo].[tblHeaderDefinition] ([pkHeaderDefinitionID], [ColumnName], [ColumnType]) VALUES (1, N'ColIntTest', N'INT')
GO
INSERT [dbo].[tblHeaderDefinition] ([pkHeaderDefinitionID], [ColumnName], [ColumnType]) VALUES (2, N'ColVarCharTest', N'VARCHAR(50)')
GO
INSERT [dbo].[tblHeaderDefinition] ([pkHeaderDefinitionID], [ColumnName], [ColumnType]) VALUES (3, N'ColRealTest', N'REAL')
GO
INSERT [dbo].[tblHeaderDefinition] ([pkHeaderDefinitionID], [ColumnName], [ColumnType]) VALUES (4, N'ColBitTest', N'BIT')
GO
SET IDENTITY_INSERT [dbo].[tblHeaderDefinition] OFF
GO
SET IDENTITY_INSERT [dbo].[tblHeaderValue] ON
GO
INSERT [dbo].[tblHeaderValue] ([pkHeaderValueID], [fkHeaderDefinitionID], [fkHeaderID], [Value]) VALUES (1, 1, 5, N'54')
GO
INSERT [dbo].[tblHeaderValue] ([pkHeaderValueID], [fkHeaderDefinitionID], [fkHeaderID], [Value]) VALUES (2, 2, 5, N'NA-0490')
GO
INSERT [dbo].[tblHeaderValue] ([pkHeaderValueID], [fkHeaderDefinitionID], [fkHeaderID], [Value]) VALUES (3, 3, 5, N'1000.094')
GO
INSERT [dbo].[tblHeaderValue] ([pkHeaderValueID], [fkHeaderDefinitionID], [fkHeaderID], [Value]) VALUES (4, 4, 5, N'1')
GO
SET IDENTITY_INSERT [dbo].[tblHeaderValue] OFF
GO
您可以使用另一个变量来保存柱的铸造:
DECLARE @collist NVARCHAR(MAX), @collist2 NVARCHAR(MAX);
SET @collist = stuff((SELECT DISTINCT ',' + QUOTENAME(ColumnName)
FROM tblHeaderDefinition
FOR XML PATH(''), TYPE
).value('.', 'NVARCHAR(MAX)')
,1,1,'')
SET @collist2 = stuff((SELECT DISTINCT ',CAST(' + QUOTENAME(ColumnName) + ' AS ' +
ColumnType + ') AS ' + QUOTENAME(ColumnName)
FROM tblHeaderDefinition
FOR XML PATH(''), TYPE
).value('.', 'NVARCHAR(MAX)')
,1,1,'')
DECLARE @q NVARCHAR(MAX)
SET @q = '
SELECT ' + @collist2 + '
FROM (
SELECT ColumnName, Value
FROM (
SELECT tblHeaderDefinition.pkHeaderDefinitionID
, tblHeaderDefinition.ColumnName
, tblHeaderDefinition.ColumnType
, tblHeaderValue.Value
FROM tblHeaderValue
INNER JOIN tblHeaderDefinition ON tblHeaderValue.fkHeaderDefinitionID = tblHeaderDefinition.pkHeaderDefinitionID
) AS x
) AS source
pivot (
max(Value)
FOR ColumnName IN (' + @collist + ')
) AS pvt
'
EXEC (@q)
这对于客户端代码来说非常容易,甚至一点都不好笑。我同意这会更容易,但在我的情况下,需要用4种不同的应用程序、4种不同的语言编写4次代码,我只能认为这会成为一场噩梦。除非你作弊,并将客户端代码变成数据库中的CLR存储过程。一段C代码。(当然,托管CLR程序集也有它自己的挑战。)这种方法只剩下一个问题,那就是WonderWare Archestra的快速脚本语言,它可以准确地描述为POS,无法访问这些类型的程序集。CLR存储过程在RPC协议和
EXEC
语句方面的功能类似于t-SQL存储过程,所以我不认为这会是一个问题。实际上,创建过程可能需要一些手动SQL。如果你真的有一种客户端语言不能使用存储过程,我很好奇这怎么可能。