Sql server SQL如何使用小计创建输出
我是T-SQL新手,需要帮助将excel报表转换为SQL运行。我有一个SQL表,记录每个仓库的所有每日库存事务(进出)。我需要创建一个报告,列出每个位置每个产品的当前库存水平和每个位置的数量,如下所示。换句话说,每个地方的当前库存水平 我还需要关于如何将首选输出报告(以下)作为视图插入SQL Server的帮助,以便我可以每月反复运行此报告 提前谢谢 库存日志表:Sql server SQL如何使用小计创建输出,sql-server,pivot-table,subtotal,Sql Server,Pivot Table,Subtotal,我是T-SQL新手,需要帮助将excel报表转换为SQL运行。我有一个SQL表,记录每个仓库的所有每日库存事务(进出)。我需要创建一个报告,列出每个位置每个产品的当前库存水平和每个位置的数量,如下所示。换句话说,每个地方的当前库存水平 我还需要关于如何将首选输出报告(以下)作为视图插入SQL Server的帮助,以便我可以每月反复运行此报告 提前谢谢 库存日志表: PubID QTY LocationID Transaction 1 10 1 Add 1
PubID QTY LocationID Transaction
1 10 1 Add
1 20 2 Add
1 30 3 Add
1 5 1 Sold
1 10 2 Sold
1 5 3 Sold
2 10 1 Add
2 10 2 Add
2 5 2 Sold
2 8 2 Sold
1 20 1 Add
1 20 2 Add
2 2 2 Sold
首选输出表:
PubID Local_1 Local_2 Local_3 Total
1 25 30 25 80
2 5 0 0 5
Total 30 30 25 85
我在这里看到了很多类似的例子,但大多数只是增加价值,而我需要从增加的库存中减去已售出的库存,以得到每列中的总数
右侧和底部的行总计和列总计是加号,但如果没有加号更容易,则不需要加号
谢谢 下面的查询满足您的需要。我可能会有一个额外的组,可以合并成1个,但你知道的
DECLARE @InventoryLog TABLE
(
PubId INT,
Qty INT,
LocationId INT,
[Transaction] Varchar(4)
)
DECLARE @LocationTable TABLE
(
Id INT,
Name VarChar(10)
)
INSERT INTO @LocationTable
VALUES
(1, 'LOC_1'),
(2, 'LOC_2'),
(3, 'LOC_3')
INSERT INTO @InventoryLog
VALUES
(1 , 10, 1 , 'Add'),
(1 , 20, 2 , 'Add'),
(1 , 30, 3 , 'Add'),
(1 , 5 , 1 , 'Sold'),
(1 , 10, 2 , 'Sold'),
(1 , 5 , 3 , 'Sold'),
(2 , 10, 1 , 'Add'),
(2 , 10, 2 , 'Add'),
(2 , 5 , 2 , 'Sold'),
(2 , 8 , 2 , 'Sold'),
(1 , 20, 1 , 'Add'),
(1 , 20, 2 , 'Add'),
(2 , 2 , 2 , 'Sold')
SELECT PubId,
lT.Name LocationName,
CASE
WHEN [Transaction] ='Add' Then Qty
WHEN [Transaction] ='Sold' Then -Qty
END as Quantity
INTO #TempInventoryTable
FROM @InventoryLog iL
INNER JOIN @LocationTable lT on iL.LocationId = lT.Id
SELECT * INTO #AlmostThere
FROM
(
SELECT PubId,
ISNULL(LOC_1,0) LOC_1,
ISNULL(LOC_2,0) LOC_2,
ISNULL(LOC_3,0) LOC_3,
SUM(ISNULL(LOC_1,0) + ISNULL(LOC_2,0) + ISNULL(LOC_3,0)) AS TOTAL
FROM #TempInventoryTable s
PIVOT
(
SUM(Quantity)
FOR LocationName in (LOC_1,LOC_2,LOC_3)
) as b
GROUP BY PubId, LOC_1, LOC_2, LOC_3
) b
SELECT CAST(PubId as VARCHAR(10))PubId,
LOC_1,
LOC_2,
LOC_3,
TOTAL
FROM #AlmostThere
UNION
SELECT ISNULL(CAST(PubId AS VARCHAR(10)),'TOTAL') PubId,
[LOC_1]= SUM(LOC_1),
[LOC_2]= SUM(LOC_2),
[LOC_3]= SUM(LOC_3),
[TOTAL]= SUM(TOTAL)
FROM #AlmostThere
GROUP BY ROLLUP(PubId)
DROP TABLE #TempInventoryTable
DROP TABLE #AlmostThere
PubId LOC_1 LOC_2 LOC_3 TOTAL
1 25 30 25 80
2 10 -5 0 5
TOTAL 35 25 25 85
如果这是关于无枢轴的聚合,则可以使用大小写表达式,如下所示:
SELECT
...
Local_1 = SUM(CASE [Transaction] WHEN 'Add' THEN QTY ELSE -QTY END),
...
FROM ...
GROUP BY ...
PubID QTY LocationID
----- --- ----------
1 10 1
1 20 2
1 30 3
1 -5 1
1 -10 2
1 -5 3
2 10 1
2 10 2
2 -5 2
2 -8 2
1 20 1
1 20 2
2 -2 2
WITH prepared AS (
SELECT
PubID,
QTY = CASE [Transaction] WHEN 'Add' THEN QTY ELSE -QTY END,
LocationID,
Total = SUM(CASE [Transaction] WHEN 'Add' THEN QTY ELSE -QTY END)
OVER (PARTITION BY PubID)
FROM dbo.InventoryLog
)
…
PubID LocationID QTY
----- ---------- ---
1 Local_1 35
2 Local_1 10
Total Local_1 45
1 Local_2 50
2 Local_2 25
Total Local_2 75
1 Local_3 35
Total Local_3 35
Total Total 155
1 Total 120
2 Total 35
但是,在PIVOT子句中,聚合函数的参数必须只是列引用,而不是表达式。您可以通过转换原始数据集来解决这一问题,使数量
为正或负,具体取决于交易
:
SELECT
PubID,
QTY = CASE [Transaction] WHEN 'Add' THEN QTY ELSE -QTY END,
LocationID
FROM dbo.InventoryLog
上述查询将为您提供如下结果集:
SELECT
...
Local_1 = SUM(CASE [Transaction] WHEN 'Add' THEN QTY ELSE -QTY END),
...
FROM ...
GROUP BY ...
PubID QTY LocationID
----- --- ----------
1 10 1
1 20 2
1 30 3
1 -5 1
1 -10 2
1 -5 3
2 10 1
2 10 2
2 -5 2
2 -8 2
1 20 1
1 20 2
2 -2 2
WITH prepared AS (
SELECT
PubID,
QTY = CASE [Transaction] WHEN 'Add' THEN QTY ELSE -QTY END,
LocationID,
Total = SUM(CASE [Transaction] WHEN 'Add' THEN QTY ELSE -QTY END)
OVER (PARTITION BY PubID)
FROM dbo.InventoryLog
)
…
PubID LocationID QTY
----- ---------- ---
1 Local_1 35
2 Local_1 10
Total Local_1 45
1 Local_2 50
2 Local_2 25
Total Local_2 75
1 Local_3 35
Total Local_3 35
Total Total 155
1 Total 120
2 Total 35
现在很容易进行旋转:
WITH prepared AS (
SELECT
PubID,
QTY = CASE [Transaction] WHEN 'Add' THEN QTY ELSE -QTY END,
LocationID
FROM dbo.InventoryLog
)
SELECT
PubID,
Local_1 = [1],
Local_2 = [2],
Local_3 = [3]
FROM prepared
PIVOT
(
SUM(QTY)
FOR LocationID IN ([1], [2], [3])
) AS p
;
请注意,您实际上可以事先准备名称Local_1
,Local_2
,Local_3
,并避免在主选择中重命名它们。假设它们是通过将LocationID
值附加到字符串Local
来形成的,下面是我的意思示例:
WITH prepared AS (
SELECT
PubID,
QTY = CASE [Transaction] WHEN 'Add' THEN QTY ELSE -QTY END,
Name = 'Local_' + CAST(LocationID AS varchar(10))
FROM dbo.InventoryLog
)
SELECT
PubID,
Local_1,
Local_2,
Local_3
FROM prepared
PIVOT
(
SUM(QTY)
FOR Name IN (Local_1, Local_2, Local_3)
) AS p
;
(由于某些结果可能为空,因此需要合并。)
但是有一种替代方法,你不需要额外一次明确列出所有的位置。您可以使用以下方法返回每个PubID
的总计以及prepared
数据集中的详细信息:
SELECT
...
Local_1 = SUM(CASE [Transaction] WHEN 'Add' THEN QTY ELSE -QTY END),
...
FROM ...
GROUP BY ...
PubID QTY LocationID
----- --- ----------
1 10 1
1 20 2
1 30 3
1 -5 1
1 -10 2
1 -5 3
2 10 1
2 10 2
2 -5 2
2 -8 2
1 20 1
1 20 2
2 -2 2
WITH prepared AS (
SELECT
PubID,
QTY = CASE [Transaction] WHEN 'Add' THEN QTY ELSE -QTY END,
LocationID,
Total = SUM(CASE [Transaction] WHEN 'Add' THEN QTY ELSE -QTY END)
OVER (PARTITION BY PubID)
FROM dbo.InventoryLog
)
…
PubID LocationID QTY
----- ---------- ---
1 Local_1 35
2 Local_1 10
Total Local_1 45
1 Local_2 50
2 Local_2 25
Total Local_2 75
1 Local_3 35
Total Local_3 35
Total Total 155
1 Total 120
2 Total 35
这将是你的全部专栏。对于行,当您熟悉分组功能时,实际上很容易添加它:
…
SELECT
PubID,
Local_1 = SUM([1]),
Local_2 = SUM([2]),
Local_3 = SUM([3]),
Total = SUM(Total)
FROM prepared
PIVOT
(
SUM(QTY)
FOR LocationID IN ([1], [2], [3])
) AS p
GROUP BY ROLLUP(PubID)
;
就这些了。总而言之,这里有一个:
最后,您可能还希望对总和应用合并,以避免在数据中返回空值(如果有必要)。还有另一种方法:在数据透视之前聚合数据,然后透视聚合的结果 与我的另一个建议相比,这个方法在语法上要简单得多,这也使得它更容易理解和维护 所有聚合都是在分组函数的帮助下完成的。基本查询如下:
SELECT
PubID,
LocationID,
QTY = SUM(CASE [Transaction] WHEN 'Add' THEN QTY ELSE -QTY END)
FROM dbo.InventoryLog
GROUP BY CUBE(PubID, LocationID)
你可以看到与我的另一个答案相同的CASE表达式,只是这次它可以直接用作SUM的参数
使用“按多维数据集聚合”不仅可以按(PubID,LocationID)
计算总数,还可以分别按PubID
和LocationID
计算总数。这是您问题中示例的查询结果:
PubID LocationID QTY
----- ---------- ---
1 1 35
2 1 10
NULL 1 45
1 2 50
2 2 25
NULL 2 75
1 3 35
NULL 3 35
NULL NULL 155
1 NULL 120
2 NULL 35
LocationID
中带null的行是最终结果集中的行总数,而PubID
中带null的行是列总数。两列中均为空的行是总计
在继续进行数据透视之前,我们需要为数据透视结果准备列名。如果名称应该从LocationID
的值派生,则以下声明将替换原始查询的SELECT子句中的LocationID
:
Location = COALESCE('Local_' + CAST(LocationID AS varchar(10)), 'Total')
PubID = COALESCE(CAST(PubID AS varchar(10)), 'Total')
在同一阶段,我们还可以用'Total'
替换PubID
中的空值,因此这将替换SELECT子句中的PubID
:
Location = COALESCE('Local_' + CAST(LocationID AS varchar(10)), 'Total')
PubID = COALESCE(CAST(PubID AS varchar(10)), 'Total')
现在,结果将如下所示:
SELECT
...
Local_1 = SUM(CASE [Transaction] WHEN 'Add' THEN QTY ELSE -QTY END),
...
FROM ...
GROUP BY ...
PubID QTY LocationID
----- --- ----------
1 10 1
1 20 2
1 30 3
1 -5 1
1 -10 2
1 -5 3
2 10 1
2 10 2
2 -5 2
2 -8 2
1 20 1
1 20 2
2 -2 2
WITH prepared AS (
SELECT
PubID,
QTY = CASE [Transaction] WHEN 'Add' THEN QTY ELSE -QTY END,
LocationID,
Total = SUM(CASE [Transaction] WHEN 'Add' THEN QTY ELSE -QTY END)
OVER (PARTITION BY PubID)
FROM dbo.InventoryLog
)
…
PubID LocationID QTY
----- ---------- ---
1 Local_1 35
2 Local_1 10
Total Local_1 45
1 Local_2 50
2 Local_2 25
Total Local_2 75
1 Local_3 35
Total Local_3 35
Total Total 155
1 Total 120
2 Total 35
在这一点上,一切都准备好应用PIVOT。根据所需格式转换上述结果集:
WITH aggregated AS (
SELECT
PubID = COALESCE(CAST(PubID AS varchar(10)), 'Total'),
Location = COALESCE('Local_' + CAST(LocationID AS varchar(10)), 'Total'),
QTY = SUM(CASE [Transaction] WHEN 'Add' THEN QTY ELSE -QTY END)
FROM dbo.InventoryLog
GROUP BY CUBE(PubID, LocationID)
)
SELECT
PubID,
Local_1,
Local_2,
Local_3,
Total
FROM aggregated
PIVOT (
MAX(QTY)
FOR Location IN (Local_1, Local_2, Local_3, Total)
) AS p
;
此查询将为缺少的
(publid,LocationID)
组合返回空值。如果您想返回0,请将COALESCE应用于aggregated
的定义中的SUM的结果。我认为这个问题可能会重复,这足以让您有理由发表一篇新文章。我见过很多类似的例子,但没有一个能做到这一点。如果你看到更多关于我是什么的问题,我愿意发表其他帖子。谢谢