以前曾经问过,但我没有找到一个与我相似的案例。如果可能的话,这应该很简单。
这些是我的表格:
CARS
ID | COLOR | TYPE
1 | 'Red' | 'Coupe'
2 | 'Blue'| 'Type1'
3 | 'Red' | 'Type2'
...
CAR_PARTS
ID | CAR_ID | PRICERED | PRICEBLUE
1 | 1 | 100 | 200
2 | 1 | 200 | 300
3 | 2 | 400 | 200
4 | 3 | 200 | 500
5 | 2 | 100 | 900
...
CAR_PARTS.CAR_ID
是绑定到ID
表的CARS
列的外键列,正如您可能已假设的那样。必须有一种方法可以让SELECT
语句返回CARS
列的TOTAL_PRICE
列,其中所有PRICERED
列都会添加到CARS.ID = CAR_PARTS.CAR_ID
所在的位置如果CARS.COLOR='Red'
为真且CARS.ID = CAR_PARTS.CAR_ID
为真,则会添加true和'CARS.COLOR='Blue'
以及所有'PRICEBLUE'列。
这样的事情:
SELECT C.ID, C.COLOR, C.TYPE,
SUM(CASE WHEN C.COLOR='Red' THEN P.PRICERED
WHEN C.COLOR='Blue' THEN P.PRICEBLUE END) AS TOTAL
FROM CARS C
JOIN CAR_PARTS P ON C.ID = P.CAR_ID
或者,正如我所尝试的,基于类似的情况:
SELECT C.ID, C.COLOR, C.TYPE, P.TOTAL
FROM CARS C
JOIN ( SELECT CAR_ID,
SUM (CASE WHEN C.COLOR='Red' THEN PRICERED
WHEN C.COLOR='Blue' THEN PRICEBLUE END) AS TOTAL
FROM CAR_PARTS
GROUP BY CAR_ID ) P ON C.ID = P.CAR_ID
显然,这些都不起作用。我明白为什么他们不工作。第一个与SQL
不明确,另一个不知道'C'
是什么。但是,如果我不希望找到解决方案,我不会在这里写一个问题。所以,我想在主GROUP BY
语句中没有SELECT
子句的情况下,如果GROUP BY
子句中有JOIN
子句,那就没关系,尽管不完美。谢谢:)。
修改:所需的输出格式
ID | COLOR | TYPE | TOTAL
1 | 'Red' | 'Coupe'| 300
2 | 'Blue'| 'Type1'| 1100
3 | 'Red' | 'Type2'| 200
因此,TOTAL
为300,因为COLOR
为'Red'
,CAR_ID=2
和COLOR='Blue'
为1100,CAR_ID=3
为200,{ {1}}。
编辑2:TL; DR(或不理解)
嗯,输出应该是整个COLOR='Red'
表,但是添加了CARS
列,该列是根据另一个TOTAL
表计算的。 CAR_PARTS
应检查汽车的SQL
,并根据汽车的CAR_ID
汇总所有PRICE
值。我希望现在更清楚了。
答案 0 :(得分:2)
好的,正如我在评论中所说的那样,你的表格设计中存在问题。你不应该像这样设计表格;它没有遵循普通形式,你最终会遇到像你这样的问题。
首先,让我们看看我们只有两种颜色:
CREATE TABLE Car (ID int IDENTITY(1,1),
Colour varchar(10),
[Type] varchar(10));
GO
CREATE TABLE CarPart (ID int IDENTITY(1,1),
CarID int,
PriceRed int,
PriceBlue int);
INSERT INTO Car (Colour, [Type])
VALUES ('Red','Coupe'),
('Blue','Type1'),
('Blue','Type2');
INSERT INTO CarPart (CarId, PriceRed, PriceBlue)
VALUES (1, 100, 200),
(1, 200, 300),
(2, 400, 200),
(3, 200, 500),
(2, 100, 900);
使用以下方法可以轻松实现您想要的结果:
SELECT C.ID,
C.Colour,
C.[Type],
SUM(CASE C.Colour WHEN 'Red' THEN CP.PriceRed
WHEN 'Blue' THEN CP.PriceBlue END) AS Total
FROM Car C
JOIN CarPart CP ON C.ID = CP.CarID
GROUP BY C.ID,
C.Colour,
C.[Type];
但是,正如你所说,可能有两种以上的颜色,如果有这意味着表CarPart
中的另一列。所以,让我们这样做:
ALTER TABLE CarPart ADD PriceGreen int;
GO
INSERT INTO Car (Colour, [Type])
VALUES ('Green','Coupe');
INSERT INTO CarPart (CarId, PriceRed, PriceBlue, PriceGreen)
VALUES (4, 500, 200, 100),
(4, 300, 700, 250);
好的,但现在我们先前的查询无法正常工作。因此,我们还必须更新Green的查询:
SELECT C.ID,
C.Colour,
C.[Type],
SUM(CASE C.Colour WHEN 'Red' THEN CP.PriceRed
WHEN 'Blue' THEN CP.PriceBlue
WHEN 'Green' THEN CP.PriceGreen END) AS Total
FROM Car C
JOIN CarPart CP ON C.ID = CP.CarID
GROUP BY C.ID,
C.Colour,
C.[Type];
真的不太好,是吗?你已经看到了问题。现在让我们为黑色添加另一列,只是为了让事情变得更加困难:
ALTER TABLE CarPart ADD PriceBlack int;
GO
INSERT INTO Car (Colour, [Type])
VALUES ('Black','Hatchback');
INSERT INTO CarPart (CarId, PriceRed, PriceBlue, PriceGreen, PriceBlack)
VALUES (5, 300, 300, 200, 200),
(5, 500, 300, 300, 400);
现在这是一个真正的问题。我们还有多少种颜色?黄色,橙色,天蓝色,绿色,洋红色?金,白,银怎么样?我可以继续列出...无论哪种方式,这个设置都很糟糕。因此,我们需要动态地解决这个问题:
DECLARE @SQL nvarchar(MAX);
SET @SQL = N'
SELECT C.ID,
C.Colour,
C.[Type],
SUM(CASE C.Colour ' + STUFF((SELECT DISTINCT NCHAR(10) + N'WHEN ''' + REPLACE(C.Colour,N'''',N'''''') + N''' THEN CP.' + QUOTENAME(N'Price' + C.Colour)
FROM Car C
FOR XML PATH(N'')),1,1,'') + N' END) AS Total
FROM Car C
JOIN CarPart CP ON C.ID = CP.CarID
GROUP BY C.ID,
C.Colour,
C.[Type];';
PRINT @SQL;
EXEC sp_executesql @SQL;
现在,无论我们添加多少列,它都能正常工作。太好了!
这是一个小附带条件,这个依赖在你的桌子CarPart
上,并且有适当的颜色列。如果表格'HotPink'
中的颜色为Car
,但表格PriceHotPink
中没有列CarPart
,那么这将会落空。如果这是一个问题,那么使用额外的逻辑定义进行评论,我会看到我能做些什么。
编辑:它还依赖于具有(完全)相同名称的列。如果表'Sky Blue'
中的值Car
,但列PriceSkyBlue
,则此值也会导致动态SQL失败;因为Dynamic SQl将尝试从列[PriceSky Blue]
返回数据。
无论哪种方式,您都需要重新考虑您的桌面设计。这不是一个可扩展的解决方案,它只会变得更糟糕"。
清理:
DROP TABLE CarPart;
DROP TABLE Car;
EDIT2:所以,没有GROUP BY
并且没有Op现在所说的额外颜色也不会被添加......
SELECT C.ID,
C.Colour,
C.[Type],
CASE C.Colour WHEN 'Red' THEN (SELECT SUM(PriceRed) FROM CarPart CP WHERE CP.CarID = C.ID)
ELSE (SELECT SUM(PRiceBlue) FROM CarPart CP WHERE CP.CarID = C.ID) END AS Total
FROM Car C;
但是,为什么你想这样做是超出我的。
答案 1 :(得分:1)
使用下面的代码
SELECT C.ID, C.COLOR, C.TYPE,
SUM(CASE WHEN C.COLOR='Red' THEN P.PRICERED
WHEN C.COLOR='Blue' THEN P.PRICEBLUE END) AS TOTAL
FROM CARS C
JOIN CAR_PARTS P
ON C.ID = P.CAR_ID
group by C.ID, C.COLOR, C.TYPE
或使用APPLY
SELECT C.ID, C.COLOR, C.TYPE, t.TOTAL
FROM CARS C
CROSS APPLY ( SELECT CAR_ID,
SUM (CASE WHEN C.COLOR='Red' THEN PRICERED
WHEN C.COLOR='Blue' THEN PRICEBLUE END) AS TOTAL
FROM CAR_PARTS
GROUP BY CAR_ID P ON C.ID = P.CAR_ID
)t
答案 2 :(得分:0)
我只需要使用OVER()
和CASE
添加另一种更简单的方法(这可以帮助您避免使用其他子查询和GROUP BY
)。
SELECT DISTINCT
Car.ID,
Car.Color,
Car.Type,
SUM(CASE WHEN Car.Color = 'Red' THEN CP.PRICERED WHEN Car.Color = 'Blue' THEN CP.PRICEBLUE END)
OVER (PARTITION BY Car.ID ORDER BY Car.ID ASC) AS TOTAL
FROM #CARS Car
JOIN #CAR_PARTS CP ON Car.ID = CP.CAR_ID