SQL动态unpivot表作为函数

时间:2017-07-16 23:02:58

标签: sql

我目前有一个查询,我用它来取消现有的表格。

表格中的一些背景信息 - 每年都会在表格中添加一个新列,以指示该年度项目ID的$值。每添加一列,就会丢弃一列。所有这些列都以&YR _'为前缀。接下来是新的一年。不断有20年的YR _'列。

我需要忽略' YR _'这些列如下所示,使我可以更轻松地利用这些信息进行多次报告 -

在开启之前 -

ProjectID    YR_16   YR_17   YR_18   YR_19   YR_20
10           0       100     20      25      100

在unpivot之后 -

ProjectID    YR      Value
10           YR_16   0
10           YR_17   100
10           YR_18   20
10           YR_19   25
10           YR_20   100

以下是我用来创建unpivot表的查询,该表将在添加/删除列时动态选取列

declare @query as NVARCHAR(max);
Declare @cols as NVARCHAR(250) = STUFF((
Select distinct ',' + QUOTENAME(Column_Name)
From INFORMATION_SCHEMA.COLUMNS
where TABLE_NAME = 'F1BWK_PLM_CAPEX'
And COLUMN_NAME like 'YR_%'
For XML Path(''), type)
.value('.','NVARCHAR(MAX)')
,1,1,'');

Select @query = 'With Unpivoted as 
(

Select * from F1BWK_PLM_CAPEX U

Unpivot (
Val
For Yr in (' + @cols + ')
)
As UnpivotTable 
)

Select U.*

From Unpivoted U
inner join [dbo].[F1_SYPAR_CTL] CTL
on CTL.value = U.WS_VERS
and CTL.PARAM_NAME like ''MBRC_CURR_PLM_BUDVER''
inner join [dbo].[F1_SYPAR_CTL] CTL2
on CTL2.value = U.WS_NAME
and CTL2.PARAM_NAME like ''MBRC_CURR_PLM_BUDWSH''';

Exec(@query);

我在将此查询转换为函数时遇到问题,以便我可以调用它并将其保存在SQL Server中,以便我的团队中的其他成员可以在需要时使用它。

这是我第一次使用unpivot表并创建函数。打开有关更改我的动态unpivot查询以满足我的需求的建议。

提前致谢

1 个答案:

答案 0 :(得分:0)

在SQL Server中,不允许在函数中使用动态SQL。

您可以创建一个SP,它将返回使用上述代码生成的记录集。

更新:

为了完整起见: 您也可以使用(OPENQUERY)调用上面的SP,这将允许您加入其他表而不必先保存到临时表,但是IMO这是一种丑陋的方式。

END UPDATE:

另一种方法是创建一个VIEW,该视图将取消此透视图并创建一个SP,在完成添加新列的过程后重新生成此视图,例如。

CREATE TABLE F1BWK_PLM_CAPEX( Val INT, Yr_17 INT, Yr_18 INT )
INSERT INTO F1BWK_PLM_CAPEX
SELECT 1, 10, 12

CREATE VIEW F1BWK_PLM_CAPEX_UNPIVOTED
AS
    SELECT *
    FROM F1BWK_PLM_CAPEX AS U
    UNPIVOT (
        Val2 FOR Yr IN (Yr_17, Yr_18)
    )
    AS UnpivotTable;

CREATE PROCEDURE dbo.Create_F1BWK_PLM_CAPEX_UNPIVOTED
AS
    SET NOCOUNT ON

    DECLARE @query as NVARCHAR(max);
    DECLARE @cols as NVARCHAR(250) =
        STUFF((
            SELECT distinct ',' + QUOTENAME( Column_Name )
            FROM INFORMATION_SCHEMA.COLUMNS
            WHERE TABLE_NAME = 'F1BWK_PLM_CAPEX'
                AND COLUMN_NAME like 'YR_%'
            For XML Path(''), type)
            .value('.','NVARCHAR(MAX)' )
        ,1,1,'');

    SELECT @query = '
    ALTER VIEW F1BWK_PLM_CAPEX_UNPIVOTED
    AS
        SELECT *
        FROM F1BWK_PLM_CAPEX AS U
        UNPIVOT (
            Val2 FOR Yr IN ( ' + @cols + ' )
        )
        AS UnpivotTable 
    ';

    EXEC(@query);
RETURN;

现在您的查询将变为:

SELECT *
FROM F1BWK_PLM_CAPEX_UNPIVOTED AS U
    INNER JOIN [dbo].[F1_SYPAR_CTL] AS CTL
        ON CTL.value = U.WS_VERS and CTL.PARAM_NAME = 'MBRC_CURR_PLM_BUDVER'
    INNER JOIN [dbo].[F1_SYPAR_CTL] AS CTL2
        ON CTL2.value = U.WS_NAME AND CTL2.PARAM_NAME = 'MBRC_CURR_PLM_BUDWSH'

在年底,会运行一个添加新列的流程:

ALTER TABLE F1BWK_PLM_CAPEX
    ADD Yr_19 INT NOT NULL DEFAULT( 10 )

此过程需要运行此SP以重新生成视图:

EXEC Create_F1BWK_PLM_CAPEX_UNPIVOTED

备注:

  • 我已将LIKE替换为=,因为您的查询与完整值匹配。仅在需要指定通配符时才使用LIKE
  • 我还通过在UNPIVOT查询
  • 中将Val更改为Val2来修复语法错误