Sql server 连接两个表,以便每次匹配时只从右表返回一行,从左表返回所有行
我有一个SQL查询,它根据给定的条件执行一个简单的左连接,如下所示Sql server 连接两个表,以便每次匹配时只从右表返回一行,从左表返回所有行,sql-server,join,Sql Server,Join,我有一个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 O
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匹配,如果三者相等,它将执行left join并给出以下结果
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)
列的值最低,如下所示
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
,并使另一个NULL
(在上述情况下为第二行)第三行当然是NULL
,因为LTR
表中没有匹配项一种方法是使用CTE。它本质上是相同的查询,但我们使用行数()
来a)根据产品、等级和术语对组进行分类,b)根据Ltrd对组进行排序。排序将每个grow中最低的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
--
为了有选择,另一种看起来更好的方法是使用outerapply
:
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
在参数内部为外部表的每一行运行查询(或者如果指定了函数而不是查询)时,这可能会执行得更糟。但有时看到这些东西是如何工作的是件好事,因为它可能会帮助以后解决另一个问题。交叉应用
和外部应用
子句非常有用一种方法是使用CTE。它本质上是相同的查询,但我们使用行数()
来a)根据产品、等级和术语对组进行分类,b)根据Ltrd对组进行排序。排序将每个grow中最低的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
--
为了有选择,另一种看起来更好的方法是使用outerapply
:
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
在参数内部为外部表的每一行运行查询(或者如果指定了函数而不是查询)时,这可能会执行得更糟。但有时看到这些东西是如何工作的是件好事,因为它可能会帮助以后解决另一个问题。交叉应用
和外部应用
子句非常有用一种方法是使用CTE。它本质上是相同的查询,但我们使用行数()
来a)根据产品、等级和术语对组进行分类,b)根据Ltrd对组进行排序。排序将每个grow中最低的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
--
为了有选择,另一种看起来更好的方法是使用outerapply
:
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
在参数内部为外部表的每一行运行查询(或者如果指定了函数而不是查询)时,这可能会执行得更糟。但有时看到这些东西是如何工作的是件好事,因为它可能会帮助以后解决另一个问题。交叉应用
和外部应用
子句非常有用一种方法是使用CTE。它本质上是相同的查询,但我们使用行数()
来a)根据产品、等级和术语对组进行分类,b)根据Ltrd对组进行排序。排序将每个grow中最低的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
--
为了有选择,另一种看起来更好的方法是使用outerapply
:
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
在参数内部为外部表的每一行运行查询(或者如果指定了函数而不是查询)时,这可能会执行得更糟。但有时看到这些东西是如何工作的是件好事,因为它可能会帮助以后解决另一个问题。交叉应用
和外部应用
子句非常有用您可以使用具有最小值的派生表作为左联接的源:
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
您可以使用具有最小值的派生表作为左联接的源:
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
您可以使用具有最小值的派生表作为左联接的源:
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
您可以使用具有最小值的派生表作为左联接的源:
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
我的预期结果不匹配yours@Dev如果您想要与CCS表中相同的订单,则只需调整第二行_编号中的order BY语句(当前显示为
a.Bid,a.Offer
)。它可以很容易地设置为a.Id
)。我刚刚更新了这些更改(我刚才提到的内容和最后的订单)。现在的输出与问题中的输出完全相同。我的预期结果不匹配yours@Dev如果您想要与CCS表中相同的订单,则只需调整第二行_编号中的order BY语句(当前显示为a.Bid,a.Offer
)。它可以很容易地设置为a.Id
)。我刚刚更新了这些更改(我刚才提到的内容和at t的订单)