Sql 动态SELECT语句,根据当前值和未来值生成列
目前正在SQL Server 2008中生成一个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_
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
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)
。