根据几个条件加入两个 table,这会导致两个 table 的一些 TOP 数据

Joining two table based on few conditions which results in some TOP data from two tables

我正在尝试通过连接两个 SQL table 和 return 第二个 table 的最新值和所有来自第一个 table 的行类似于左连接以及来自 table2 的 TOP 1 记录,其中 table1 中没有匹配项,按产品、等级、术语

分组

我的问题可以用下面的例子清楚地解释。

Table1

Id  Product Grade Term Bid Offer 
100 ABC       A   Q1   10  20
101 ABC       A   Q1   5   25
102 XYZ       A   Q2   25  30
103 XYZ       B   Q2   20  30

Table2

Id Product Grade Term TradeValue
1  ABC     A     Q1     100
2  ABC     A     Q1     95    
3  XYZ     B     Q2     100
4  PQR     C     Q2     100
5  PQR     C     Q2     200

在上面的数据中,我想加入 Table1Table2,只要 table 的列 Product,Grade and Term 相等且 return来自 Table1 的所有行,同时将来自 Table2 的列 TradeValue 的最新值连接到匹配的第一条记录,并为结果视图的其他行制作 TradeValue as NULL 和结果视图应该有 Table2Id 作为 LTID 并且它也应该 return 来自 Table 2 的 TOP 1 行,其中 Product、Grade 和 Term 不是按产品、等级和期限进行平等分组

所以结果 SQL 视图应该是

结果

   Id  Product Grade Term Bid Offer TradeValue LTID
   100  ABC       A   Q1   10   20    100         2
   101  ABC       A   Q1   5    25    NULL       NULL
   102  XYZ       A   Q2   25   30    NULL       NULL
   103  XYZ       B   Q2   20   30    100         3
   104  PQR       C   Q2   NULL NULL  200         5 

我尝试使用以下查询

http://sqlfiddle.com/#!3/e8884/7

我们可以看到 TradeValue 的最新值被分配给 Table1 中的所有匹配行,而且我无法 return 来自 [=67= 的 TOP 1 行]2 未找到匹配项

我可以知道更好的处理方法吗?

试试这个:

SELECT ROW_NUMBER() OVER(ORDER BY d.Product) as ID,d.*,t1.Bid,t1.Offer,t2.LastTradeValue,t2.ID AS LTID 
FROM
(
  SELECT Product,Grade,Term
  FROM Table1
  UNION 
  SELECT Product,Grade,Term
  FROM Table2 
) d
LEFT JOIN Table1 t1 ON d.Product=t1.Product AND d.Grade=t1.Grade AND d.Term=t1.Term
OUTER APPLY 
(
  SELECT TOP 1 * FROM Table2 t2 WHERE d.Product=t2.Product AND d.Grade=t2.Grade AND d.Term=t2.Term
  ORDER BY t2.ID DESC
) t2

由于您使用的是 Sql Server 2012,所以我建议如下:

DECLARE @t1 TABLE
    (
      Id INT ,
      Product CHAR(3) ,
      Grade CHAR(1) ,
      Term CHAR(2) ,
      Bid INT ,
      Offer INT
    )
DECLARE @t2 TABLE
    (
      Id INT ,
      Product CHAR(3) ,
      Grade CHAR(1) ,
      Term CHAR(2) ,
      TradeValue INT
    )

INSERT  INTO @t1
VALUES  ( 100, 'ABC', 'A', 'Q1', 10, 20 ),
        ( 101, 'ABC', 'A', 'Q1', 5, 25 ),
        ( 102, 'XYZ', 'A', 'Q2', 25, 30 ),
        ( 103, 'XYZ', 'B', 'Q2', 20, 30 )

INSERT  INTO @t2
VALUES  ( 1, 'ABC', 'A', 'Q1', 100 ),
        ( 2, 'ABC', 'A', 'Q1', 95 ),
        ( 3, 'XYZ', 'B', 'Q2', 100 ),
        ( 4, 'PQR', 'C', 'Q2', 100 ),
        ( 5, 'PQR', 'C', 'Q2', 200 ),
        ( 6, 'TTT', 'C', 'Q2', 200 ),
        ( 7, 'TTT', 'C', 'Q2', 201 ),
        ( 8, 'JJJ', 'C', 'Q2', 500 );

WITH    cte
          AS ( SELECT   t1.Id AS t1Id ,
                        t1.Product AS t1Product ,
                        t1.Grade AS t1Grade ,
                        t1.Term AS t1Term ,
                        t1.Bid AS t1Bid ,
                        t1.Offer AS t1Offer ,
                        IIF(t1.ID IS NULL, t1.Id, t2.Id) AS ordert2Id ,
                        t2.Id AS t2Id ,
                        t2.Product AS t2Product ,
                        t2.Grade AS t2Grade ,
                        t2.Term AS t2Term ,
                        t2.TradeValue AS t2TradeValue
               FROM     @t2 t2
                        FULL JOIN @t1 t1 ON t2.Product = t1.Product
                                            AND t2.Grade = t1.Grade
                                            AND t2.Term = t1.Term
             ),
        cte2
          AS ( SELECT   * ,
                        ROW_NUMBER() OVER ( PARTITION BY t2Product, t2Grade, t2Term, t1Id ORDER BY ordert2Id ) AS rn1 ,
                        RANK() OVER ( PARTITION BY t2Product, t2Grade, t2Term ORDER BY t1Id ) AS rn2 ,
                        LAST_VALUE(t2TradeValue) OVER ( PARTITION BY t2Product, t2Grade, t2Term ORDER BY ordert2Id ROWS BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING ) AS TradeValue ,
                        LAST_VALUE(t2Id) OVER ( PARTITION BY t2Product, t2Grade, t2Term ORDER BY t2Id ROWS BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING ) AS TradeId
               FROM     cte
             )
    SELECT  t1Id AS ID ,
            ISNULL(t1Product, t2Product) AS Product ,
            ISNULL(t1Grade, t2Grade) AS Product ,
            ISNULL(t1Term, t2Term) AS Product ,
            t1Bid AS Bid ,
            t1Offer AS Offer,
            IIF(rn2 = 1, TradeValue, NULL) AS TradeValue,
            IIF(rn2 = 1, TradeId, NULL) AS LTID

    FROM    cte2
    WHERE   rn1 = 1

输出:

ID   Product    Product Product Bid  Offer  TradeValue  LTID
NULL PQR        C       Q2      NULL NULL   200         5
100  ABC        A       Q1      10   20     95          2
101  ABC        A       Q1      5    25     NULL        NULL
102  XYZ        A       Q2      25   30     NULL        NULL
103  XYZ        B       Q2      20   30     100         3