在SQL查询中添加总行(数据透视表)

huangapple go评论59阅读模式
英文:

Add Total Row in SQL Query (Pivot)

问题

这是查询部分,不要翻译:

SELECT 
  *, 
  ISNULL([In Use], 0.) + ISNULL([Used - In Store], 0.) + ISNULL([In Store], 0.) + ISNULL([New - In Store], 0.) + ISNULL([Damaged], 0.) + ISNULL([Faulty], 0.) AS TOTAL 
FROM 
  (
    SELECT 
      max("product"."COMPONENTNAME") AS "Product", 
      max("state"."DISPLAYSTATE") AS "Asset State", 
      count("resource"."RESOURCENAME") AS "Asset Count" 
    FROM 
      "Resources" "resource" 
      LEFT JOIN "ComponentDefinition" "product" ON "resource"."COMPONENTID" = "product"."COMPONENTID" 
      LEFT JOIN "ResourceState" "state" ON "resource"."RESOURCESTATEID" = "state"."RESOURCESTATEID" 
      LEFT JOIN "ResourceOwner" "rOwner" ON "resource"."RESOURCEID" = "rOwner"."RESOURCEID" 
      LEFT JOIN "ResourceAssociation" "rToAsset" ON "rOwner"."RESOURCEOWNERID" = "rToAsset"."RESOURCEOWNERID" 
      LEFT JOIN "SDUser" "sdUser" ON "rOwner"."USERID" = "sdUser"."USERID" 
      LEFT JOIN "AaaUser" "aaaUser" ON "sdUser"."USERID" = "aaaUser"."USER_ID" 
    WHERE 
      product.COMPONENTNAME LIKE ('Thinkpad%') 
    GROUP BY 
      "product"."COMPONENTNAME", 
      "state"."DISPLAYSTATE"
  ) d pivot (
    sum("Asset Count") for "Asset State" in (
      [In Use], [Used - In Store], [In Store], 
      [New - In Store], [Damaged], [Faulty]
    )
  ) piv

如果您需要进一步的翻译或帮助,请告诉我。

英文:

We are using a asset management software and unfortunatly unable to get the proper support in DIY implementation. I was looking to get an asset report (Laptop Count based on model and state).

With the help of google I manage to create a pivot for the required report. Now, I am stuck with the last part of the task. which is to get a total row for asset state e.g. (In - Store, New - In Store) at the bottom.

This is the Query and I am unable to understand how to add the total row.

SELECT 
*, 
ISNULL([In Use], 0.) + ISNULL([Used - In Store], 0.) + ISNULL([In Store], 0.) + ISNULL([New - In Store], 0.) + ISNULL([Damaged], 0.) + ISNULL([Faulty], 0.) AS TOTAL 
FROM 
(
SELECT 
max("product"."COMPONENTNAME") AS "Product", 
max("state"."DISPLAYSTATE") AS "Asset State", 
count("resource"."RESOURCENAME") AS "Asset Count" 
FROM 
"Resources" "resource" 
LEFT JOIN "ComponentDefinition" "product" ON "resource"."COMPONENTID" = "product"."COMPONENTID" 
LEFT JOIN "ResourceState" "state" ON "resource"."RESOURCESTATEID" = "state"."RESOURCESTATEID" 
LEFT JOIN "ResourceOwner" "rOwner" ON "resource"."RESOURCEID" = "rOwner"."RESOURCEID" 
LEFT JOIN "ResourceAssociation" "rToAsset" ON "rOwner"."RESOURCEOWNERID" = "rToAsset"."RESOURCEOWNERID" 
LEFT JOIN "SDUser" "sdUser" ON "rOwner"."USERID" = "sdUser"."USERID" 
LEFT JOIN "AaaUser" "aaaUser" ON "sdUser"."USERID" = "aaaUser"."USER_ID" 
WHERE 
product.COMPONENTNAME LIKE ('Thinkpad%') 
GROUP BY 
"product"."COMPONENTNAME", 
"state"."DISPLAYSTATE"
) d pivot (
sum("Asset Count") for "Asset State" in (
[In Use], [Used - In Store], [In Store], 
[New - In Store], [Damaged], [Faulty]
)
) piv

在SQL查询中添加总行(数据透视表)

答案1

得分: 1

以下是代码部分的翻译:

  • 在维度中自动生成总计,您可以使用GROUP BY ... WITH CUBE。这将添加一个总计行,并且还会消除显式计算总计列的需求。

  • ISNULL()用于为分组的产品和状态名称分配标签,否则将为null。[Total]也已添加到数据透视列表,并从最终选择列表中删除。如果您希望将空值替换为零,可能需要编辑选择列表以添加ISNULL()函数(例如,ISNULL([In Use], 0) AS [In Use], ...)。

  • 结果:

产品 在使用 在库存中使用 存储中 新库存中使用 损坏 故障 总计
Thinkpad 101 2 2 3 1 1 1 10
Thinkpad 102 1 null null null null null 1
Thinkpad 103 null null null null 1 1 2
总计: 3 2 3 1 2 2 13
  • 您还可以使用GROUP BY ... WITH ROLLUP为行编写类似的结果,并使用"条件聚合"来定义列,作为数据透视的替代。

  • "条件聚合"是一种非正式术语,用于将聚合函数如SUM()COUNT()CASE表达式一起使用。如果条件为真,THEN子句提供要聚合的数据。当条件为假时,隐式的ELSE null值将被忽略。

  • 结果:

产品 在使用 在库存中使用 存储中 新库存中使用 损坏 故障 总计
Thinkpad 101 2 2 3 1 1 1 10
Thinkpad 102 1 0 0 0 0 0 1
Thinkpad 103 0 0 0 0 1 1 2
总计 3 2 3 1 2 2 13

希望这对您有所帮助。

英文:

You can use GROUP BY ... WITH CUBE to automatically generate totals in both dimensions. This will add a totals row and will also eliminate the need to explicitly calculate the totals column.

SELECT piv.*
FROM (
SELECT 
ISNULL(product."COMPONENTNAME", 'Totals:') AS "Product", 
ISNULL(state."DISPLAYSTATE", 'TOTAL') AS "Asset State", 
count(resource."RESOURCENAME") AS "Asset Count" 
FROM 
"Resources" "resource" 
LEFT JOIN "ComponentDefinition" "product" ON "resource"."COMPONENTID" = "product"."COMPONENTID" 
LEFT JOIN "ResourceState" "state" ON "resource"."RESOURCESTATEID" = "state"."RESOURCESTATEID" 
LEFT JOIN "ResourceOwner" "rOwner" ON "resource"."RESOURCEID" = "rOwner"."RESOURCEID" 
LEFT JOIN "ResourceAssociation" "rToAsset" ON "rOwner"."RESOURCEOWNERID" = "rToAsset"."RESOURCEOWNERID" 
LEFT JOIN "SDUser" "sdUser" ON "rOwner"."USERID" = "sdUser"."USERID" 
LEFT JOIN "AaaUser" "aaaUser" ON "sdUser"."USERID" = "aaaUser"."USER_ID" 
WHERE 
product.COMPONENTNAME LIKE ('Thinkpad%') 
GROUP BY 
product."COMPONENTNAME", 
state."DISPLAYSTATE"
WITH CUBE
) d
pivot (
sum("Asset Count") for "Asset State" in (
[In Use], [Used - In Store], [In Store], 
[New - In Store], [Damaged], [Faulty],
[TOTAL])
) piv
ORDER BY
CASE WHEN piv.Product = 'Totals:' THEN 2 ELSE 1 END,
piv.Product

ISNULL() is used to assign labels to the grouped product and status names, which would otherwise be null. [Total] has also been added to the pivot list and removed from the final select list. You may need to edit the select list to add ISNULL() functions if you want to replace null values with zeros. (E.g., ISNULL([In Use], 0) AS [In Use], ...)

Results:

Product In Use Used - In Store In Store New - In Store Damaged Faulty TOTAL
Thinkpad 101 2 2 3 1 1 1 10
Thinkpad 102 1 null null null null null 1
Thinkpad 103 null null null null 1 1 2
Totals: 3 2 3 1 2 2 13

You can also code a similar result using GROUP BY ... WITH ROLLUP for the rows together with "conditional aggregation" to define the columns as a replacement for the pivot.

SELECT
ISNULL(product.COMPONENTNAME, 'Total') AS Product,
COUNT(CASE WHEN state.DISPLAYSTATE = 'In Use' THEN 1 END) AS [In Use],
COUNT(CASE WHEN state.DISPLAYSTATE = 'Used - In Store' THEN 1 END) AS [Used - In Store],
COUNT(CASE WHEN state.DISPLAYSTATE = 'In Store' THEN 1 END) AS [In Store],
COUNT(CASE WHEN state.DISPLAYSTATE = 'New - In Store' THEN 1 END) AS [New - In Store],
COUNT(CASE WHEN state.DISPLAYSTATE = 'Damaged' THEN 1 END) AS [Damaged],
COUNT(CASE WHEN state.DISPLAYSTATE = 'Faulty' THEN 1 END) AS [Faulty],
COUNT(*) AS TOTAL
FROM 
"Resources" "resource" 
LEFT JOIN "ComponentDefinition" "product" ON "resource"."COMPONENTID" = "product"."COMPONENTID" 
LEFT JOIN "ResourceState" "state" ON "resource"."RESOURCESTATEID" = "state"."RESOURCESTATEID" 
LEFT JOIN "ResourceOwner" "rOwner" ON "resource"."RESOURCEID" = "rOwner"."RESOURCEID" 
LEFT JOIN "ResourceAssociation" "rToAsset" ON "rOwner"."RESOURCEOWNERID" = "rToAsset"."RESOURCEOWNERID" 
LEFT JOIN "SDUser" "sdUser" ON "rOwner"."USERID" = "sdUser"."USERID" 
LEFT JOIN "AaaUser" "aaaUser" ON "sdUser"."USERID" = "aaaUser"."USER_ID" 
WHERE 
product.COMPONENTNAME LIKE ('Thinkpad%') 
GROUP BY product.COMPONENTNAME WITH ROLLUP
ORDER BY
CASE WHEN GROUPING(product.COMPONENTNAME) = 0 THEN 1 ELSE 2 END,
product.COMPONENTNAME

"Conditional aggregation" is an informal term for usieng aggregation functions like SUM() or COUNT() together with a CASE expression. If the condition is true, the THEN clause provides the data to be aggregated. When false, the implicit ELSE null value is ignored.

Results:

Product In Use Used - In Store In Store New - In Store Damaged Faulty TOTAL
Thinkpad 101 2 2 3 1 1 1 10
Thinkpad 102 1 0 0 0 0 0 1
Thinkpad 103 0 0 0 0 1 1 2
Total 3 2 3 1 2 2 13

See this db<>fiddle for examples of both using simplified test data.

答案2

得分: 0

您可以使用'UNION'来将两个查询连接在一起,以获取总行数;它可能是这样的:

SELECT *, ISNULL([In Use], 0.) + ISNULL([Used - In Store], 0.) + ISNULL([In Store], 0.) + ISNULL([New - In Store], 0.) + ISNULL([Damaged], 0.) + ISNULL([Faulty], 0.) AS TOTAL
FROM (
SELECT max("product"."COMPONENTNAME") AS "Product", max("state"."DISPLAYSTATE") AS "Asset State", count("resource"."RESOURCENAME") AS "Asset Count" FROM "Resources" "resource"
LEFT JOIN "ComponentDefinition" "product" ON "resource"."COMPONENTID"="product"."COMPONENTID"
LEFT JOIN "ResourceState" "state" ON "resource"."RESOURCESTATEID"="state"."RESOURCESTATEID"
LEFT JOIN "ResourceOwner" "rOwner" ON "resource"."RESOURCEID"="rOwner"."RESOURCEID" LEFT JOIN "ResourceAssociation" "rToAsset" ON "rOwner"."RESOURCEOWNERID"="rToAsset"."RESOURCEOWNERID" LEFT JOIN "SDUser" "sdUser" ON "rOwner"."USERID"="sdUser"."USERID" LEFT JOIN "AaaUser" "aaaUser" ON "sdUser"."USERID"="aaaUser"."USER_ID"
WHERE product.COMPONENTNAME LIKE 'ThinkPad %'
GROUP BY "product"."COMPONENTNAME","state"."DISPLAYSTATE")d
UNION
SELECT "Totals:", ISNULL([In Use], 0.) + ISNULL([Used - In Store], 0.) + ISNULL([In Store], 0.) + ISNULL([New - In Store], 0.) + ISNULL([Damaged], 0.) + ISNULL([Faulty], 0.) AS TOTAL
FROM (
SELECT max("product"."COMPONENTNAME") AS "Product", max("state"."DISPLAYSTATE") AS "Asset State", count("resource"."RESOURCENAME") AS "Asset Count" FROM "Resources" "resource"
LEFT JOIN "ComponentDefinition" "product" ON "resource"."COMPONENTID"="product"."COMPONENTID"
LEFT JOIN "ResourceState" "state" ON "resource"."RESOURCESTATEID"="state"."RESOURCESTATEID"
LEFT JOIN "ResourceOwner" "rOwner" ON "resource"."RESOURCEID"="rOwner"."RESOURCEID" LEFT JOIN "ResourceAssociation" "rToAsset" ON "rOwner"."RESOURCEOWNERID"="rToAsset"."RESOURCEOWNERID" LEFT JOIN "SDUser" "sdUser" ON "rOwner"."USERID"="sdUser"."USERID" LEFT JOIN "AaaUser" "aaaUser" ON "sdUser"."USERID"="aaaUser"."USER_ID"
WHERE product.COMPONENTNAME LIKE 'ThinkPad %'
GROUP BY "state"."DISPLAYSTATE")d
<details>
<summary>英文:</summary>
You could use &#39;UNION&#39; to join two queries together to give you a total row; it&#39;d be something like:

SELECT *, ISNULL([In Use], 0.) + ISNULL([Used - In Store], 0.) + ISNULL([In Store], 0.) + ISNULL([New - In Store], 0.) + ISNULL([Damaged], 0.) + ISNULL([Faulty], 0.) AS TOTAL
FROM (
SELECT max("product"."COMPONENTNAME") AS "Product", max("state"."DISPLAYSTATE") AS "Asset State", count("resource"."RESOURCENAME") AS "Asset Count" FROM "Resources" "resource"
LEFT JOIN "ComponentDefinition" "product" ON "resource"."COMPONENTID"="product"."COMPONENTID"
LEFT JOIN "ResourceState" "state" ON "resource"."RESOURCESTATEID"="state"."RESOURCESTATEID"
LEFT JOIN "ResourceOwner" "rOwner" ON "resource"."RESOURCEID"="rOwner"."RESOURCEID" LEFT JOIN "ResourceAssociation" "rToAsset" ON "rOwner"."RESOURCEOWNERID"="rToAsset"."RESOURCEOWNERID" LEFT JOIN "SDUser" "sdUser" ON "rOwner"."USERID"="sdUser"."USERID" LEFT JOIN "AaaUser" "aaaUser" ON "sdUser"."USERID"="aaaUser"."USER_ID"
WHERE product.COMPONENTNAME LIKE 'ThinkPad %'
GROUP BY "product"."COMPONENTNAME","state"."DISPLAYSTATE")d

UNION

SELECT "Totals:", ISNULL([In Use], 0.) + ISNULL([Used - In Store], 0.) + ISNULL([In Store], 0.) + ISNULL([New - In Store], 0.) + ISNULL([Damaged], 0.) + ISNULL([Faulty], 0.) AS TOTAL
FROM (
SELECT max("product"."COMPONENTNAME") AS "Product", max("state"."DISPLAYSTATE") AS "Asset State", count("resource"."RESOURCENAME") AS "Asset Count" FROM "Resources" "resource"
LEFT JOIN "ComponentDefinition" "product" ON "resource"."COMPONENTID"="product"."COMPONENTID"
LEFT JOIN "ResourceState" "state" ON "resource"."RESOURCESTATEID"="state"."RESOURCESTATEID"
LEFT JOIN "ResourceOwner" "rOwner" ON "resource"."RESOURCEID"="rOwner"."RESOURCEID" LEFT JOIN "ResourceAssociation" "rToAsset" ON "rOwner"."RESOURCEOWNERID"="rToAsset"."RESOURCEOWNERID" LEFT JOIN "SDUser" "sdUser" ON "rOwner"."USERID"="sdUser"."USERID" LEFT JOIN "AaaUser" "aaaUser" ON "sdUser"."USERID"="aaaUser"."USER_ID"
WHERE product.COMPONENTNAME LIKE 'ThinkPad %'
GROUP BY "state"."DISPLAYSTATE")d

huangapple
  • 本文由 发表于 2023年2月6日 02:24:59
  • 转载请务必保留本文链接:https://go.coder-hub.com/75354536.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定