Warning: file_get_contents(/data/phpspider/zhask/data//catemap/7/sql-server/25.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Sql server 连接两个表,以便每次匹配时只从右表返回一行,从左表返回所有行_Sql Server_Join - Fatal编程技术网

Sql server 连接两个表,以便每次匹配时只从右表返回一行,从左表返回所有行

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

我有一个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匹配,如果三者相等,它将执行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的订单)