我有一个SQL查询,它根据给定的条件执行简单的左连接,如下所示
SELECT
a.Product,a.Grade,a.Term,a.Bid,
a.Offer,b.Ltrd
FROM CCS AS a
left JOIN LTR AS b ON b.Product=a.Product
and b.Grade=a.Grade
and b.Term=a.Term
我有两个表CCS和LTR以及以下数据
CCS Table
Id Product Grade Term Bid Offer
1 Xyz A Jan 20 30
2 XYz A Jan 25 35
3 abc B Feb 25 30
LTR Table
Id Product Grade Term Ltrd
1 Xyz A Jan 500
2 XYz A Jan 400
运行上面的查询时,它看起来与产品,等级,期限匹配,如果三者相等,则执行左连接并给出以下结果
Product Grade Term Bid Offer Ltrd
Xyz A Jan 20 30 500
Xyz A Jan 20 30 400
XYz A Jan 25 35 500
XYz A Jan 25 35 400
abc B Feb 25 30 NULL
上面的返回了5行,我尝试只获得表CCS
中的三行,其中Ltrd(ie 400)
表中列LTR
的值最小,如下所示
Product Grade Term Bid Offer Ltrd
Xyz A Jan 20 30 400
Xyz A Jan 25 35 NULL
abc B Feb 25 30 NULL
在Ltrd
列中的上述结果中,我只想从LTR
表中的匹配中获取最低值,并将其分配给第一行中的Ltrd
并生成另一个{{1} (在上面的第二行中)和第三行当然是NULL
因为NULL
表中没有匹配
答案 0 :(得分:2)
一种方法是使用CTE。它本质上是相同的查询,但我们使用ROW_NUMBER()
来a)根据产品,成绩和成绩,和b)根据 Ltrd 在这些组中排序。排序将每个增长中的最低 Ltrd 值推送到每个组的第一行,然后我们只选择每个组的第一行。
DECLARE @CCS TABLE (Id INT, Product VARCHAR(20), Grade VARCHAR(5), Term VARCHAR(5),
Bid INT, Offer INT);
INSERT INTO @CCS VALUES (1, 'Xyz', 'A', 'Jan', 20, 30);
INSERT INTO @CCS VALUES (2, 'XYz', 'A', 'Jan', 25, 35);
INSERT INTO @CCS VALUES (3, 'abc', 'B', 'Feb', 25, 30);
DECLARE @LTR TABLE (Id INT, Product VARCHAR(20), Grade VARCHAR(5), Term VARCHAR(5),
Ltrd INT)
INSERT INTO @LTR VALUES (1, 'Xyz', 'A', 'Jan', 500);
INSERT INTO @LTR VALUES (2, 'XYz', 'A', 'Jan', 400);
;WITH cte AS
(
SELECT b.Product, b.Grade, b.Term, b.Ltrd,
ROW_NUMBER() OVER
(PARTITION BY b.Product, b.Grade, b.Term ORDER BY b.Ltrd ASC)
AS [RowNum]
FROM @LTR b
)
SELECT a.Product, a.Grade, a.Term, a.Bid, a.Offer,
CASE WHEN ROW_NUMBER()
OVER (PARTITION BY a.Product, a.Grade, a.Term ORDER BY a.Id ASC) = 1
THEN b.Ltrd
ELSE NULL
END AS [Ltrd]
FROM @CCS a
LEFT JOIN cte b
ON b.Product = a.Product
AND b.Grade = a.Grade
AND b.Term = a.Term
AND b.RowNum = 1
ORDER BY a.Id ASC;
结果:
Product Grade Term Bid Offer Ltrd
Xyz A Jan 20 30 400
XYz A Jan 25 35 NULL
abc B Feb 25 30 NULL
-
只是为了获得选项,另一种看起来更好的方法是使用OUTER APPLY
:
SELECT a.Product, a.Grade, a.Term, a.Bid, a.Offer,
CASE WHEN ROW_NUMBER() OVER
(PARTITION BY a.Product, a.Grade, a.Term ORDER BY a.Bid, a.Offer ASC)
= 1 THEN c.Ltrd
ELSE NULL END AS [Ltrd]
FROM @CCS a
OUTER APPLY (SELECT TOP (1) b.Ltrd
FROM @LTR b
WHERE b.Product = a.Product
AND b.Grade = a.Grade
AND b.Term = a.Term
ORDER BY b.Ltrd ASC
) c
结果是一样的。这可能会更糟糕,因为OUTER APPLY
为外部表的每一行运行查询内部的查询(或者如果指定了函数而不是查询)。但有时很高兴看到这些东西如何工作,因为它可能有助于以后解决不同的问题。 CROSS APPLY
和OUTER APPLY
条款非常有用
答案 1 :(得分:1)
您可以使用具有最小值的派生表作为左连接的源:
SELECT
a.Product,
a.Grade,
a.Term,
a.Bid,
a.Offer,
CASE
WHEN ROW_NUMBER() OVER (PARTITION BY a.Product ORDER BY a.Id) = 1
THEN b.Ltrd ELSE NULL
END AS LTRD
FROM CCS AS a
LEFT JOIN (
SELECT Product, Grade, Term, MIN(ltrd) ltrd
FROM LTR
GROUP BY Product, Grade, term
) AS b
ON b.Product = a.Product
AND b.Grade = a.Grade
AND b.Term = a.Term
ORDER BY a.Id