LEFT JOIN 不 return 所有值
LEFT JOIN doesn't return all values
我有以下表格:
create table Cars
(
CarID int,
CarType varchar(50)
);
create table Maintenances
(
CarID int,
MaintenanceDate date,
MaintenanceCost money
);
create table Repairs
(
CarID int,
RepairDate date,
RepairCost money
);
我试过这个:
SELECT C.CarType,
SUM(MaintenanceCost),
SUM(RepairCost)
FROM Cars AS C
LEFT JOIN Maintenances AS M ON M.CarID=C.CarID
LEFT JOIN Repairs AS R ON R.CarID=C.CarID
WHERE M.MaintenanceDate BETWEEN '2020-12-01' AND '2020-12-31' AND
R.RepairDate BETWEEN '2020-12-01' AND '2020-12-31'
GROUP BY C.CarType
但它并不是所有 CarType 的 return 值。看到这个 fiddle:Fiddle
将 LEFT JOIN
ed table 上的条件从 WHERE
子句移动到联接的 ON
子句 - 否则,它们将成为强制性的,而不是- 过滤掉 table 中的匹配行。
所以:
SELECT C.CarType, SUM(M.MaintenanceCost), SUM(R.RepairCost)
FROM Cars AS C
LEFT JOIN Maintenances M
ON M.CarID = C.CarID
AND M.MaintenanceDate BETWEEN '20201201' AND '20201231'
LEFT JOIN Repairs R
ON R.CarID = C.CarID
AND R.RepairDate BETWEEN '20201201' AND '20201231'
GROUP BY C.CarType
旁注:
我在 SUM()
中的列前面加上它们所属的 table 前缀(我不得不猜测):这是很好的做法,并且使查询自-解释性的,明确的
YYYYMMDD
在 SQL 服务器的所有版本中都支持作为日期文字,无论区域设置如何,因此它可能是比 YYYY-MM-DD
更好的选择
那是因为您是按维护和维修日期过滤的 table。在 tables.
中,只有 CarID 3 具有您给定日期范围的条目
如果您希望结果包含您日期范围内的所有车型,您可以试试这个查询。
SELECT C.CarType,
ISNULL(SUM(MaintenanceCost),0) AS MaintenanceCost,
ISNULL(SUM(RepairCost),0) AS RepairCost
Cars AS C
JOIN Maintenances AS M
M.CarID = C.CarID
M.MaintenanceDate BETWEEN '2020-12-01' AND '2020-12-31'
JOIN Repairs AS R
R.CarID = C.CarID
R.RepairDate BETWEEN '2020-12-01' AND '2020-12-31'
BY C.CarType
如果您希望 SUM()
正确,我建议使用相关子查询编写此逻辑。问题是你最终得到每个 Carid
的笛卡尔积——笛卡尔积意味着总和计算正确:
如果CarType
在Cars
中是唯一的,你可以使用:
SELECT C.CarType,
(SELECT SUM(M.MaintenanceCost)
FROM Maintenances M
WHERE M.CarID = C.CarID AND
M.MaintenanceDate BETWEEN '20201201' AND '20201231'
),
(SELECT SUM(R.RepairCost)
FROM Repairs R
WHERE R.CarID = R.CarID AND
R.RepairDate BETWEEN '20201201' AND '20201231'
)
FROM Cars C ;
否则,这看起来有点复杂,因为您需要在每个子查询中使用 CarType
:
SELECT C.CarType,
(SELECT SUM(M.MaintenanceCost)
FROM Maintenances M JOIN
Cars C
ON M.CarID = C.CarID
WHERE C.CarType = CT.CarType AND
M.MaintenanceDate BETWEEN '20201201' AND '20201231'
),
(SELECT SUM(R.RepairCost)
FROM Repairs R JOIN
Cars C
ON R.CarID = C.CarID
WHERE C.CarType = CT.CarType AND
R.RepairDate BETWEEN '20201201' AND '20201231'
)
FROM (SELECT DISTINCT CarType FROM Cars C) CT
我有以下表格:
create table Cars
(
CarID int,
CarType varchar(50)
);
create table Maintenances
(
CarID int,
MaintenanceDate date,
MaintenanceCost money
);
create table Repairs
(
CarID int,
RepairDate date,
RepairCost money
);
我试过这个:
SELECT C.CarType,
SUM(MaintenanceCost),
SUM(RepairCost)
FROM Cars AS C
LEFT JOIN Maintenances AS M ON M.CarID=C.CarID
LEFT JOIN Repairs AS R ON R.CarID=C.CarID
WHERE M.MaintenanceDate BETWEEN '2020-12-01' AND '2020-12-31' AND
R.RepairDate BETWEEN '2020-12-01' AND '2020-12-31'
GROUP BY C.CarType
但它并不是所有 CarType 的 return 值。看到这个 fiddle:Fiddle
将 LEFT JOIN
ed table 上的条件从 WHERE
子句移动到联接的 ON
子句 - 否则,它们将成为强制性的,而不是- 过滤掉 table 中的匹配行。
所以:
SELECT C.CarType, SUM(M.MaintenanceCost), SUM(R.RepairCost)
FROM Cars AS C
LEFT JOIN Maintenances M
ON M.CarID = C.CarID
AND M.MaintenanceDate BETWEEN '20201201' AND '20201231'
LEFT JOIN Repairs R
ON R.CarID = C.CarID
AND R.RepairDate BETWEEN '20201201' AND '20201231'
GROUP BY C.CarType
旁注:
我在
SUM()
中的列前面加上它们所属的 table 前缀(我不得不猜测):这是很好的做法,并且使查询自-解释性的,明确的YYYYMMDD
在 SQL 服务器的所有版本中都支持作为日期文字,无论区域设置如何,因此它可能是比YYYY-MM-DD
更好的选择
那是因为您是按维护和维修日期过滤的 table。在 tables.
中,只有 CarID 3 具有您给定日期范围的条目如果您希望结果包含您日期范围内的所有车型,您可以试试这个查询。
SELECT C.CarType,
ISNULL(SUM(MaintenanceCost),0) AS MaintenanceCost,
ISNULL(SUM(RepairCost),0) AS RepairCost
Cars AS C
JOIN Maintenances AS M
M.CarID = C.CarID
M.MaintenanceDate BETWEEN '2020-12-01' AND '2020-12-31'
JOIN Repairs AS R
R.CarID = C.CarID
R.RepairDate BETWEEN '2020-12-01' AND '2020-12-31'
BY C.CarType
如果您希望 SUM()
正确,我建议使用相关子查询编写此逻辑。问题是你最终得到每个 Carid
的笛卡尔积——笛卡尔积意味着总和计算正确:
如果CarType
在Cars
中是唯一的,你可以使用:
SELECT C.CarType,
(SELECT SUM(M.MaintenanceCost)
FROM Maintenances M
WHERE M.CarID = C.CarID AND
M.MaintenanceDate BETWEEN '20201201' AND '20201231'
),
(SELECT SUM(R.RepairCost)
FROM Repairs R
WHERE R.CarID = R.CarID AND
R.RepairDate BETWEEN '20201201' AND '20201231'
)
FROM Cars C ;
否则,这看起来有点复杂,因为您需要在每个子查询中使用 CarType
:
SELECT C.CarType,
(SELECT SUM(M.MaintenanceCost)
FROM Maintenances M JOIN
Cars C
ON M.CarID = C.CarID
WHERE C.CarType = CT.CarType AND
M.MaintenanceDate BETWEEN '20201201' AND '20201231'
),
(SELECT SUM(R.RepairCost)
FROM Repairs R JOIN
Cars C
ON R.CarID = C.CarID
WHERE C.CarType = CT.CarType AND
R.RepairDate BETWEEN '20201201' AND '20201231'
)
FROM (SELECT DISTINCT CarType FROM Cars C) CT