2

我坚持实现一个存储过程来生成具有动态列的视图。此视图应代表以下 PIVOT SQL 语句,如下所示:

SQL 小提琴演示

为什么我使用带有动态 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
4

1 回答 1

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 初始化它)

于 2013-10-31T08:52:17.977 回答