获得此输出的最佳SQL代码

时间:2012-07-05 22:17:32

标签: sql sql-server sqlite

简单地说,   我有这些表。

Planning: 
  Date | Machine | Product | PlanningParts

OKParts: 
  Date | Machine | Product | OKParts

Scrap: 
  Date | Machine | Product | ScrapParts

Trials: 
  Date | Machine | Product | TrialParts

Breakdowns: 
  Date | Machine | Product | Minutes

这些表可以有两个或多个相同[Date |机器|产品],它们不是唯一的列。  获得此输出的最佳SQL代码(SQLite或SQL Server)是什么?

Output:
  Date | Machine | Product | Planning | OKParts | ScrapParts | TrialParts | Minutes

编辑: 在输出中,我需要每[Date,Machine,Product]一行,其余列必须是SUM (我不会说英语,抱歉)

Eidted: 例: (我不会把表格“试验”缩短)

Planning:
     Date    | Machine | Product | PlanningParts
     1/6/12  |  Blower | A001    | 100
     2/6/12  |  Blower | A002    | 100
     2/6/12  | Assembly| B001    | 50

OKParts:
     Date   | Machine | Product  | OKParts
     1/6/12 | Blower  | A001     | 50
     1/6/12 | Blower  | A001     | 20
     1/6/12 | Blower  | A002     | 100

Scrap:
     Date   | Machine | Product  | ScrapParts | Reason
     1/6/12 | Blower  | A001     | 5          | Low Weight
     1/6/12 | Blower  | A001     | 3          | High Weight
     2/6/12 | Assembly| B001     | 4          | Bad Cut

Breakdowns
     Date   | Machine | Product  | Minutes    | Reason
     1/6/12 | Blower  | A001     | 100        | Manteinance
     1/6/12 | Blower  | A001     | 20         | Manteinance
     2/6/12 | Assembly| B001     | 100        | Quality approval


   OUTPUT:
         Date   | Machine | Product  | Planning | OKParts | ScrapParts | Breakdowns
         1/6/12 | Blower  | A001     | 100      | 70      | 8          | 120
         1/6/12 | Blower  | A002     | 100      | 100     | 0          | 0
         2/6/12 | Assembly| B001     | 50       | 0       | 4          | 100

2 个答案:

答案 0 :(得分:3)

创建一个CTE将所有表合并为一个,然后使用SUM聚合函数,为每个Date,Machine,Product组添加列。有点像这样(未经测试):

WITH AllParts AS (
SELECT Date, Machine, Product, PlanningParts, NULL AS OKParts, NULL AS ScrapParts, NULL AS TrialParts, NULL AS Breakdowns
FROM Planning
UNION ALL
SELECT Date, Machine, Product,NULL AS PlanningParts, OKParts, NULL AS ScrapParts, NULL AS TrialParts, NULL AS Breakdowns
FROM OKParts
UNION ALL
SELECT Date, Machine, Product,NULL AS PlanningParts, NULL AS OKParts, ScrapParts, NULL AS TrialParts, NULL AS Breakdowns
FROM Scrap
UNION ALL
SELECT Date, Machine, Product,NULL AS PlanningParts, NULL AS OKParts, NULL AS ScrapParts, TrialParts, NULL AS Breakdowns
FROM Trials
UNION ALL
SELECT Date, Machine, Product,NULL AS PlanningParts, NULL AS OKParts, NULL AS ScrapParts, TrialParts, Breakdowns
FROM BreakDowns
)
SELECT
Date, Machine, Product, SUM(OKParts) AS OKParts, SUM(ScrapParts) AS ScrapParts, SUM(TrialParts) AS TrialParts, SUM(BreakDowns) AS Breakdowns
FROM AllParts
GROUP BY Date, Machine, Product

答案 1 :(得分:1)

我有兴趣看看UNION之后的SUMming是否与第一个SUM的查询一样好:

WITH Vals AS (
   SELECT Date, Machine, Product, 'PlanningParts' Which, Sum(PlanningParts) Value FROM Planning GROUP BY Date, Machine, Product
   UNION ALL SELECT Date, Machine, Product, 'OKParts', Sum(OKParts) FROM OKParts GROUP BY Date, Machine, Product
   UNION ALL SELECT Date, Machine, Product, 'ScrapParts', Sum(ScrapParts) FROM Scrap GROUP BY Date, Machine, Product
   UNION ALL SELECT Date, Machine, Product, 'TrialParts', Sum(TrialParts) FROM Trials GROUP BY Date, Machine, Product
   UNION ALL SELECT Date, Machine, Product, 'Minutes', Sum(Minutes) FROM Breakdowns GROUP BY Date, Machine, Product
)
SELECT *
FROM Vals
PIVOT (Max(Value) FOR Which IN (PlanningParts, OKParts, ScrapParts, TrialParts, Minutes)) P;

是的,这很痛苦,但这就是你从给定的数据库设计中获得的。将这5个表重构为一个表,其中视图替换这些表具有替代触发器可能是可行的。

注意:PIVOT适用于SQL Server 2005及更高版本。但你甚至不需要PIVOT:

WITH Vals AS (
   SELECT Date, Machine, Product, 'PlanningParts' Which, Sum(PlanningParts) Value FROM Planning GROUP BY Date, Machine, Product
   UNION ALL SELECT Date, Machine, Product, 'OKParts', Sum(OKParts) FROM OKParts GROUP BY Date, Machine, Product
   UNION ALL SELECT Date, Machine, Product, 'ScrapParts', Sum(ScrapParts) FROM Scrap GROUP BY Date, Machine, Product
   UNION ALL SELECT Date, Machine, Product, 'TrialParts', Sum(TrialParts) FROM Trials GROUP BY Date, Machine, Product
   UNION ALL SELECT Date, Machine, Product, 'Minutes', Sum(Minutes) FROM Breakdowns GROUP BY Date, Machine, Product
)
SELECT
   Date, Machine, Product,
   Sum(CASE Which WHEN 'PlanningParts' THEN Value END) PlanningParts,
   Sum(CASE Which WHEN 'OKParts' THEN Value END) OKParts,
   Sum(CASE Which WHEN 'ScrapParts' THEN Value END) ScrapParts,
   Sum(CASE Which WHEN 'TrialParts' THEN Value END) TrialParts,
   Sum(CASE Which WHEN 'Minutes' THEN Value END) Minutes
FROM Vals;

将文本Which值切换为整数可能会提高速度。

关于我对表中包含日期,机器,产品值的明确列表的表的评论/问题,此查询将提供此类列表。这不会很好,但它应该给你这个想法。

WITH DistinctKeys AS ( --wishing we had this as a real table
   SELECT Date, Machine, Product FROM Planning
   UNION SELECT Date, Machine, Product FROM OKParts
   UNION SELECT Date, Machine, Product FROM Scrap
   UNION SELECT Date, Machine, Product FROM Trials
   UNION SELECT Date, Machine, Product FROM Breakdown
) -- because then we could do this:
SELECT
   K.Date, K.Machine, K.Part,
   (SELECT Sum(PlanningParts) FROM Planning X ON EXISTS (SELECT K.* INTERSECT SELECT X.Date, X.Machine, X.Product) PlanningParts
   (SELECT Sum(OKParts) FROM OKParts X ON EXISTS (SELECT K.* INTERSECT SELECT X.Date, X.Machine, X.Product) OKParts
   (SELECT Sum(ScrapParts) FROM Scrap X ON EXISTS (SELECT K.* INTERSECT SELECT X.Date, X.Machine, X.Product) Scrap
   (SELECT Sum(TrialParts) FROM Trials X ON EXISTS (SELECT K.* INTERSECT SELECT X.Date, X.Machine, X.Product) TrialParts
   (SELECT Sum(Minutes) FROM Breakdown X ON EXISTS (SELECT K.* INTERSECT SELECT X.Date, X.Machine, X.Product) Minutes
FROM
   DistinctKeys K;

但坦率地说,JOINs的表现不如我之前和@jaypeagi的回答中提供的UNION一样好。

还有一件事:不要假设查询的性能是什么。甚至专家也会检查执行计划并收集真实的IO和CPU统计信息以确定此信息。您对NULL降低性能的担忧可能完全没有根据。

如果您在[日期,机器,产品]上的表上有良好的索引,那么您可能会从UNION方法中获得相当好的性能。