通过存储过程创建具有动态列的视图
Posted
技术标签:
【中文标题】通过存储过程创建具有动态列的视图【英文标题】:Creating View with dynamic columns by stored procedure 【发布时间】:2013-10-31 08:45:02 【问题描述】:我一直在实现一个存储过程来生成具有动态列的视图。 该视图应代表如下 PIVOT SQL 语句,如下所示:
SQL Fiddle Demo
为什么我使用带有动态 SQL 的存储过程? 要求是,要实现一个数据库对象,其行为类似于目前在 MSSQL 2005 上以及从 9i 开始的 Oracle 上工作的所示语句(不幸的是......)。 现在,由于缺少有关如何以更好的方式实现的更深入的知识,我决定使用存储过程。
但现在我卡住了,任何建议都非常感谢。也欢迎任何关于如何以更好的方式实现但结果与 SQL Fiddle Demo 相同的建议。
我的 SP 目前看起来像这样:
create procedure GeneratePivotLeistungsbewertungen
as
SET NOCOUNT ON;
DECLARE cActivityNames CURSOR FOR
SELECT distinct ActivityName
FROM Leistungsbewertungen
DECLARE @name VARCHAR(32)
DECLARE @dyn_col_list NVARCHAR(MAX)
OPEN cActivityNames
FETCH NEXT FROM cActivityNames INTO @name
WHILE @@FETCH_STATUS = 0
BEGIN
SET @dyn_col_list = @dyn_col_list + N'(select lb.Bewertungswert from Leistungsbewertungen lb where lb.ActivityName = '+ @name +' and lb.LeistungsId = o.LeistungsId)' + @name + ','
FETCH NEXT FROM cActivityNames INTO @name
END
deallocate cActivityNames
select LEFT(@dyn_col_list, LEN(@dyn_col_list)-1)
DECLARE @execVar NVARCHAR(MAX) = N' VIEW dbo.PivotLeistungsbewertungen
AS
SELECT max(o.LeistungsId) LeistungsId, max(o.Gnr) GOP,' + @dyn_col_list +
'FROM leistungen o group by o.LeistungsId'
SET @execVar = CASE WHEN EXISTS
(SELECT 1 FROM sys.views WHERE [object_id] = OBJECT_ID('dbo.PivotLeistungsbewertungen'))
THEN N'ALTER' ELSE N'CREATE' + @execVar END;
BEGIN TRY
EXEC sp_executesql @execVar;
END TRY
BEGIN CATCH
PRINT ERROR_MESSAGE();
END CATCH
go
如果您这样称呼它,为什么它不创建视图的任何想法:
USE [Q20133_0_NO]
GO
DECLARE @return_value int
EXEC @return_value = [dbo].[GeneratePivotLeistungsbewertungen]
SELECT 'Return Value' = @return_value
GO
为解决方案编辑 (2005/2008R2)
更新了有效的存储过程(在 SQLServer 2008 R2 下测试
CREATE PROCEDURE GeneratePivotLeistungsbewertungen
AS
SET NOCOUNT ON;
DECLARE @name VARCHAR(32)
DECLARE @dyn_col_list NVARCHAR(MAX) = ''
SELECT @dyn_col_list = isnull(@dyn_col_list + ',', '') + N'(
select lb.Bewertungswert
from Leistungsbewertungen lb
where
lb.ActivityName = ''' + ActivityName + ''' and
lb.LeistungsId = o.LeistungsId
)' + ActivityName
FROM Leistungsbewertungen
GROUP BY ActivityName
DECLARE @execVar NVARCHAR(MAX) = N' VIEW dbo.PivotLeistungsbewertungen
AS
SELECT max(o.LeistungsId) LeistungsId, max(o.Gnr) GOP' + @dyn_col_list + ' FROM leistungen o group by o.LeistungsId'
SET @execVar = CASE
WHEN EXISTS (
SELECT 1
FROM sys.VIEWS
WHERE [object_id] = OBJECT_ID('dbo.PivotLeistungsbewertungen')
)
THEN N'ALTER' + @execVar
ELSE N'CREATE' + @execVar
END;
BEGIN TRY
EXEC sp_executesql @execVar;
END TRY
BEGIN CATCH
PRINT ERROR_MESSAGE();
END CATCH
对于 SQLServer 2005,它必须遵循实施(也适用于 2008 R2)
DECLARE @execVar NVARCHAR(200)
SET @execVar = CASE
WHEN EXISTS (
SELECT 1
FROM sys.procedures
WHERE [object_id] = OBJECT_ID('dbo.GeneratePivotLeistungsbewertungen')
)
THEN N'DROP PROCEDURE GeneratePivotLeistungsbewertungen;'
END;
EXEC(@execVar)
go
CREATE PROCEDURE GeneratePivotLeistungsbewertungen
AS
SET NOCOUNT ON;
DECLARE @name VARCHAR(32)
DECLARE @dyn_col_list NVARCHAR(MAX)
SET @dyn_col_list = ''
SELECT @dyn_col_list = isnull(@dyn_col_list + ',', '') + N'(
select lb.Bewertungswert
from Leistungsbewertungen lb
where
lb.ActivityName = ''' + ActivityName + ''' and
lb.LeistungsId = o.LeistungsId
) AS ' + ActivityName
FROM Leistungsbewertungen
GROUP BY ActivityName
ORDER BY MAX(Bewertungsschritt)
DECLARE @execVar NVARCHAR(MAX)
SET @execVar = N' VIEW dbo.PivotLeistungsbewertungenView
AS
SELECT max(o.LeistungsId) LeistungsId, max(o.Gnr) GOP' + @dyn_col_list + ' FROM leistungen o group by o.LeistungsId'
SET @execVar = CASE
WHEN EXISTS (
SELECT 1
FROM sys.VIEWS
WHERE [object_id] = OBJECT_ID('dbo.PivotLeistungsbewertungenView')
)
THEN N'ALTER' + @execVar
ELSE N'CREATE' + @execVar
END;
BEGIN TRY
EXEC sp_executesql @execVar;
END TRY
BEGIN CATCH
PRINT ERROR_MESSAGE();
END CATCH
GO
【问题讨论】:
【参考方案1】:我几乎可以肯定,您只需初始化 @dyn_col_list
就可以了:
set @dyn_col_list = ''
在打开光标之前。无论如何,如果你有这样的问题,快速检查它的最好方法是在执行之前print @execVar
以确保你到底在执行什么。
另外,我通常使用这种语法而不是光标:
select
@dyn_col_list = isnull(@dyn_col_list + ',', '') +
N'(
select lb.Bewertungswert
from Leistungsbewertungen lb
where
lb.ActivityName = '+ ActivityName +' and
lb.LeistungsId = o.LeistungsId
)' + ActivityName
from Leistungsbewertungen
group by ActivityName
它更短,自动消除最后一个逗号,并且您不需要初始化@dyn_col_list
(实际上,如果有可能它可能不为空,则您不必初始化它或用null初始化它)
【讨论】:
好的,在将变量分配给自身之前初始化变量是有意义的。感谢那。现在有一件事,用select LEFT(@dyn_col_list, LEN(@dyn_col_list)-1)
在列列表中删除最后一个逗号是正确的方法吗?它告诉我“ from 语句附近的语法错误”。最后一个逗号不会被截断。 或者,也许有一种方法可以识别 while 语句中的最后一个循环,以便决定是否必须添加逗号?
如何在我的 SP 中实施您的更新?如果我只是复制粘贴它,我只会得到结果的最后一列。该选择将给出 n 个可能的结果。 (我以前从未对 MSSQL Sps 做过什么,我目前正在学习语法)
@Dom84 是啊,改了答案,不完全正确以上是关于通过存储过程创建具有动态列的视图的主要内容,如果未能解决你的问题,请参考以下文章