我正在创建一个视图作为报告,将来自各种表的行数据显示为列,在某些情况下涉及连接。当我使用临时表时,我的查询效果很好,但它需要是一个视图,我正在努力将临时表方法转换为子查询。
我创建了几个示例表和数据来尽可能简化这个问题。这是架构:
CREATE TABLE [Car] (
[CarId] [int] NOT NULL,
[Name] [varchar](50) NOT NULL,
CONSTRAINT [PK_Car] PRIMARY KEY CLUSTERED ([CarId] ASC))
INSERT INTO [Car] VALUES
(1, 'Honda')
CREATE TABLE [Part] (
[PartId] [int] IDENTITY(1,1) NOT NULL,
[CarId] [int] NOT NULL,
[Name] [varchar](50) NOT NULL,
[PercentComplete] [decimal](3, 2) NOT NULL,
CONSTRAINT [PK_Part] PRIMARY KEY CLUSTERED ([PartId] ASC))
INSERT INTO [Part] VALUES
(1, 'Engine', 0.5)
,(1, 'Transmission', 0.75)
,(1, 'Suspension', 0.3)
这是初始步骤:
SELECT
c.CarId
,c.Name AS [CarName]
,p.Name AS [PartName]
,p.PercentComplete AS [PartPercentComplete]
INTO #Temp
FROM Car c
JOIN Part p
ON p.CarId = c.CarId
这是将其转换为我的报告视图的分组选择:
SELECT
MAX(CarName) AS [Car Name]
,STUFF((
SELECT ', ' + [PartName]
FROM #Temp
WHERE (CarId = t1.CarId)
FOR XML PATH (''))
,1,2,'') AS [Parts]
,MAX(CASE [PartCompleteAvg] WHEN 1.00 THEN 'Complete' ELSE 'Incomplete' END) AS [Part Status]
,MAX(CASE [PartId] WHEN [LatestPartId] THEN [PartName] ELSE NULL END) AS [Latest Part]
FROM (
SELECT
CarId
,AVG(PartPercentComplete) AS [PartCompleteAvg]
,MAX(PartId) AS [LatestPartId]
FROM #Temp
GROUP BY CarId
) t1
LEFT JOIN #Temp t2
ON t2.CarId = t1.CarId
GROUP BY t1.CarId
它工作得非常好,除了由于中间聚合函数AVG(PartPercentComplete)
和与STUFF
. 我的报告需要其中的几个。
我知道我不能嵌套AVG()
在里面MAX()
,因为这给了Cannot perform an aggregate function on an expression containing an aggregate or a subquery.
(仅供参考,我知道,PIVOT
但它需要跨越多个列,尽管我意识到这也是可能的,CASE
似乎更容易,而且我被告知更快。)
我完全不正确和糟糕的尝试:
SELECT
MAX(CarName) AS [Car Name]
,STUFF((
SELECT ', ' + [PartName]
FROM #Temp
WHERE (CarId = t1.CarId)
FOR XML PATH (''))
,1,2,'') AS [Parts]
,MAX(CASE [PartCompleteAvg] WHEN 1.00 THEN 'Complete' ELSE 'Incomplete' END) AS [Part Status]
FROM (
SELECT
CarId
,AVG(PartPercentComplete) AS [PartCompleteAvg]
FROM (
SELECT
c.CarId
,c.Name AS [CarName]
,p.Name AS [PartName]
,p.PercentComplete AS [PartPercentComplete]
FROM Car c
JOIN Part p
ON p.CarId = c.CarId
) t1
GROUP BY CarId
) t1
LEFT JOIN #Temp t2
ON t2.CarId = t1.CarId
GROUP BY t1.CarId
显然#Temp
在这两个位置都是无效的。我不是 SQL 专家,我希望有一种干净且相对简单的方法可以做到这一点,甚至可以避免自加入。
编辑
我添加了
MAX(PartId) AS [LatestPartId]
和
MAX(CASE [PartId] WHEN [LatestPartId] THEN [PartName] ELSE NULL END) AS [Latest Part]
因为这是一个更好的例子,说明为什么我需要一个中间GROUP BY
.