Warning: file_get_contents(/data/phpspider/zhask/data//catemap/5/sql/75.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Sql 动态SELECT语句,根据当前值和未来值生成列_Sql_Sql Server 2008_Cursor_Pivot Table - Fatal编程技术网

Sql 动态SELECT语句,根据当前值和未来值生成列

Sql 动态SELECT语句,根据当前值和未来值生成列,sql,sql-server-2008,cursor,pivot-table,Sql,Sql Server 2008,Cursor,Pivot Table,目前正在SQL Server 2008中生成一个SELECT语句,但希望使该SELECT语句成为动态的,因此可以根据表中的值定义列。我听说过透视表和游标,但在我目前的水平上似乎有点难以理解,下面是代码 DECLARE @date DATE = null IF @date is null set @ date = GETDATE() as DATE SELECT Name, value1, value2, value3, value4 FROM ref_

目前正在SQL Server 2008中生成一个
SELECT
语句,但希望使该
SELECT
语句成为动态的,因此可以根据表中的值定义列。我听说过透视表和游标,但在我目前的水平上似乎有点难以理解,下面是代码

DECLARE @date DATE = null

IF @date is null
set @ date = GETDATE() as DATE

SELECT
    Name,
    value1,
    value2,
    value3,
    value4
FROM ref_Table a
FULL OUTER JOIN (
    SELECT
       PK_ID ID,
       sum(case when FK_ContainerType_ID = 1 then 1 else null) Box,
       sum(case when FK_ContainerType_ID = 2 then 1 else null) Pallet,
       sum(case when FK_ContainerType_ID = 3 then 1 else null) Bag,
       sum(case when FK_ContainerType_ID = 4 then 1 else null) Drum
    from 
       Packages  
    WHERE 
       @date between PackageStart AND PackageEnd
    group by PK_ID ) b on a.Name = b.ID
where 
    Group = 0
下面的内容对我来说非常有用,但是PK_Type_ID和列的名称(PackageNameX,…)是硬编码的,我需要动态的,它可以基于
Package
表中的当前值或未来值构建自身

如果您能在正确的方向上提供任何帮助或指导,我们将不胜感激

应要求

ref\u表
(主键ID,名称)

包装
(主键标识、FK\u参考表标识、FK\u集装箱类型标识、包装开始日期、包装结束日期)

容器类型
(主键ID,类型)

结果应该是这样的

Name     Box     Pallet    Bag    Drum
---------------------------------------
John                                1
Mary                        1
Albert              1
Jane       1

正如我所说,下面的代码非常有效,问题是
容器
表将增长,我需要复制相同的报告,而无需对列进行硬编码。

您需要构建的称为动态透视。若你们搜索那个术语,在堆栈上有很多很好的参考文献

以下是您的场景的解决方案:

IF OBJECT_ID('tempdb..##ref_Table') IS NOT NULL
    DROP TABLE ##ref_Table
IF OBJECT_ID('tempdb..##Packages') IS NOT NULL
    DROP TABLE ##Packages
IF OBJECT_ID('tempdb..##ContainerType') IS NOT NULL
    DROP TABLE ##ContainerType

SET NOCOUNT ON

CREATE TABLE ##ref_Table (PK_ID INT, NAME NVARCHAR(50))
CREATE TABLE ##Packages (PK_ID INT, FK_ref_Table_ID INT, FK_ContainerType_ID INT, PackageStartDate DATE, PackageEndDate DATE)
CREATE TABLE ##ContainerType (PK_ID INT, [Type] NVARCHAR(50))

INSERT INTO ##ref_Table (PK_ID,NAME)
SELECT 1,'John' UNION
SELECT 2,'Mary' UNION
SELECT 3,'Albert' UNION
SELECT 4,'Jane'

INSERT INTO ##Packages (PK_ID, FK_ref_Table_ID, FK_ContainerType_ID, PackageStartDate, PackageEndDate)
SELECT 1,1,4,'2014-01-01','2014-01-30' UNION
SELECT 2,2,3,'2014-01-01','2014-01-30' UNION
SELECT 3,3,2,'2014-01-01','2014-01-30' UNION
SELECT 4,4,1,'2014-01-01','2014-01-30' 

INSERT INTO ##ContainerType (PK_ID, [Type])
SELECT 1,'Box' UNION
SELECT 2,'Pallet' UNION
SELECT 3,'Bag' UNION
SELECT 4,'Drum' 

DECLARE @DATE DATE, @PARAMDEF NVARCHAR(MAX), @COLS NVARCHAR(MAX), @SQL NVARCHAR(MAX)
SET @DATE = '2014-01-15'

SET @COLS = STUFF((SELECT DISTINCT  ',' + QUOTENAME(T.[Type])
            FROM ##ContainerType T
            FOR XML PATH, TYPE).value('.', 'NVARCHAR(MAX)'),1,1,'')

SET @SQL = 'SELECT [Name], ' + @COLS + ' 
            FROM (SELECT [Name], [Type], 1 AS Value
                  FROM ##ref_Table R
                  JOIN ##Packages P ON R.PK_ID = P.FK_ref_Table_ID
                  JOIN ##ContainerType T ON P.FK_ContainerType_ID = T.PK_ID
                  WHERE @DATE BETWEEN P.PackageStartDate AND P.PackageEndDate) X
            PIVOT (COUNT(Value) FOR [Type] IN (' + @COLS + ')) P
            '
PRINT @COLS
PRINT @SQL
SET @PARAMDEF = '@DATE DATE'
EXEC SP_EXECUTESQL @SQL, @PARAMDEF, @DATE=@DATE
输出:

Name    Bag     Box     Drum    Pallet
Albert  0       0       0       1
Jane    0       1       0       0
John    0       0       1       0
Mary    1       0       0       0

静态查询:

SELECT [Name],[Box],[Pallet],[Bag],[Drum] FROM
(
    SELECT *
    FROM
    (
        SELECT  rf.Name,cnt.[Type], pk.PK_ID AS PKID, rf.PK_ID AS RFID
        FROM ref_Table rf INNER JOIN Packages pk ON rf.PK_ID = pk.FK_ref_Table_ID
        INNER JOIN ContanerType cnt ON cnt.PK_ID = pk.FK_ContainerType_ID
     ) AS SourceTable
    PIVOT
    (
           COUNT(PKID )
           FOR [Type]
           IN ( [Box],[Pallet],[Bag],[Drum])
    ) AS PivotTable
) AS Main
ORDER BY RFID
DECLARE @columnList nvarchar (MAX)
DECLARE @pivotsql nvarchar (MAX)

SELECT @columnList =   STUFF(
             (
             SELECT ',' + '[' + [Type] + ']'
           FROM ContanerType
           FOR XML PATH( '')
           )
        ,1, 1,'' )


SET @pivotsql =
N'SELECT [Name],' + @columnList + ' FROM
(
    SELECT *
    FROM
    (
        SELECT  rf.Name,cnt.[Type], pk.PK_ID AS PKID, rf.PK_ID AS RFID
        FROM ref_Table rf INNER JOIN Packages pk ON rf.PK_ID = pk.FK_ref_Table_ID
        INNER JOIN ContanerType cnt ON cnt.PK_ID = pk.FK_ContainerType_ID
     ) AS SourceTable
    PIVOT
    (
           COUNT(PKID )
           FOR [Type]
           IN ( ' + @columnList + ')
    ) AS PivotTable
) AS Main
ORDER BY RFID;'

EXEC sp_executesql @pivotsql


动态查询:

SELECT [Name],[Box],[Pallet],[Bag],[Drum] FROM
(
    SELECT *
    FROM
    (
        SELECT  rf.Name,cnt.[Type], pk.PK_ID AS PKID, rf.PK_ID AS RFID
        FROM ref_Table rf INNER JOIN Packages pk ON rf.PK_ID = pk.FK_ref_Table_ID
        INNER JOIN ContanerType cnt ON cnt.PK_ID = pk.FK_ContainerType_ID
     ) AS SourceTable
    PIVOT
    (
           COUNT(PKID )
           FOR [Type]
           IN ( [Box],[Pallet],[Bag],[Drum])
    ) AS PivotTable
) AS Main
ORDER BY RFID
DECLARE @columnList nvarchar (MAX)
DECLARE @pivotsql nvarchar (MAX)

SELECT @columnList =   STUFF(
             (
             SELECT ',' + '[' + [Type] + ']'
           FROM ContanerType
           FOR XML PATH( '')
           )
        ,1, 1,'' )


SET @pivotsql =
N'SELECT [Name],' + @columnList + ' FROM
(
    SELECT *
    FROM
    (
        SELECT  rf.Name,cnt.[Type], pk.PK_ID AS PKID, rf.PK_ID AS RFID
        FROM ref_Table rf INNER JOIN Packages pk ON rf.PK_ID = pk.FK_ref_Table_ID
        INNER JOIN ContanerType cnt ON cnt.PK_ID = pk.FK_ContainerType_ID
     ) AS SourceTable
    PIVOT
    (
           COUNT(PKID )
           FOR [Type]
           IN ( ' + @columnList + ')
    ) AS PivotTable
) AS Main
ORDER BY RFID;'

EXEC sp_executesql @pivotsql

下面的教程将帮助您了解PIVOT功能:

我们编写sql查询是为了从数据库表中获得不同的结果集,如完整、部分、计算、分组、排序等。然而,有时我们需要轮换桌子。听起来很困惑

让我们保持简单,考虑下面两个屏幕抓取。

SQL表:

预期结果:

哇,看起来工作量很大!这是复杂的sql、临时表、循环、聚合……等等的组合

别担心,让我们保持简单,愚蠢(亲吻

MS SQL Server 2005及更高版本有一个名为PIVOT的函数。它使用非常简单,功能强大。借助此函数,我们将能够旋转sql表和结果集

实现这一目标的简单步骤:

SELECT [Name],[Box],[Pallet],[Bag],[Drum] FROM
(
    SELECT *
    FROM
    (
        SELECT  rf.Name,cnt.[Type], pk.PK_ID AS PKID, rf.PK_ID AS RFID
        FROM ref_Table rf INNER JOIN Packages pk ON rf.PK_ID = pk.FK_ref_Table_ID
        INNER JOIN ContanerType cnt ON cnt.PK_ID = pk.FK_ContainerType_ID
     ) AS SourceTable
    PIVOT
    (
           COUNT(PKID )
           FOR [Type]
           IN ( [Box],[Pallet],[Bag],[Drum])
    ) AS PivotTable
) AS Main
ORDER BY RFID
DECLARE @columnList nvarchar (MAX)
DECLARE @pivotsql nvarchar (MAX)

SELECT @columnList =   STUFF(
             (
             SELECT ',' + '[' + [Type] + ']'
           FROM ContanerType
           FOR XML PATH( '')
           )
        ,1, 1,'' )


SET @pivotsql =
N'SELECT [Name],' + @columnList + ' FROM
(
    SELECT *
    FROM
    (
        SELECT  rf.Name,cnt.[Type], pk.PK_ID AS PKID, rf.PK_ID AS RFID
        FROM ref_Table rf INNER JOIN Packages pk ON rf.PK_ID = pk.FK_ref_Table_ID
        INNER JOIN ContanerType cnt ON cnt.PK_ID = pk.FK_ContainerType_ID
     ) AS SourceTable
    PIVOT
    (
           COUNT(PKID )
           FOR [Type]
           IN ( ' + @columnList + ')
    ) AS PivotTable
) AS Main
ORDER BY RFID;'

EXEC sp_executesql @pivotsql
  • 确定将成为所需结果集一部分的所有列
  • 查找我们将应用聚合的列(总和、平均值、最大值、最小值等)
  • 确定将哪些值作为列标题的列
  • 指定步骤3中提到的列值,用逗号分隔并用方括号括起来
  • 因此,如果我们现在按照上述四个步骤,从上述销售表中提取信息,将如下所示:

  • 年、月、销售额
  • 销售额
  • 【一月】、【二月】、【三月】。。。。等
  • 如果到目前为止,以上所有步骤对您都有意义,那么我们就快到了

    现在我们有了我们需要的所有信息。我们现在要做的就是在下面的模板中填写所需信息。 模板: 我们的SQL查询应该如下所示:

    挑选*

    FROM
    (
        SELECT SalesYear, SalesMonth,Amount
        FROM Sales
     ) AS SourceTable
    PIVOT
    (
           SUM(Amount )
           FOR SalesMonth
           IN ( [Jan],[Feb] ,[Mar],
                [Apr],[May],[Jun] ,[Jul],
                [Aug],[Sep] ,[Oct],[Nov] ,[Dec])
    ) AS PivotTable;
    
    在上面的查询中,我们硬编码了列名。当你必须指定许多列的时候,这并不有趣

    然而,有一项工作如下:

    DECLARE @columnList nvarchar (MAX)
    DECLARE @pivotsql nvarchar (MAX)
    
    SELECT @columnList =   STUFF(
                 (
                   SELECT ',' + '[' + SalesMonth + ']'
                   FROM Sales
                   GROUP BY SalesMonth
                   FOR XML PATH( '')
               )
            ,1, 1,'' )
    
    SET @pivotsql =
           N'SELECT *
          FROM
          (
                SELECT SalesYear, SalesMonth,Amount
                FROM Sales
           ) AS SourceTable
          PIVOT
          (
               SUM(Amount )
               FOR SalesMonth
               IN ( ' + @columnList +' )
          ) AS PivotTable;'
    
    EXEC sp_executesql @pivotsql
    
    希望本教程能对某些人有所帮助。
    喜欢编码。

    您能提供一个包含一些示例数据和预期输出示例的模式吗?注意:如果您希望看到
    NULL
    而不是0表示缺少的数据,请将动态SQL字符串中的
    COUNT(Value)
    更改为
    SUM(Value)