繁体   English   中英

一对一左连接

[英]One to one left join

如何在每个类别中仅使用一对一行进行左连接。 这是类别ID和产品价格。 请注意,如果我使用LEFT JOIN,我不希望在第5类中出现重复重复。

外适用

(1)最合适的连接是每个表中的类别和价格都匹配。 这是第二类的情况(注意表A和B中的行顺序不同)
(2)如果只有类别匹配,那么我想显示任何行的字段(就像我在第一类中所做的那样,信息是它是多行之一)。
(3)如果类别和价格都不匹配,我想得到NULL。

我使用了以下查询,但对我来说太慢了。

with 
A as (select A.id, A.price 
,ROW_NUMBER() over(partition BY id) as Row_id_A
,ROW_NUMBER() OVER(PARTITION BY id, price order by price asc) AS [Row_id_price_A]
from TableA as A)
,
B as (select B.id, B.price, B.field
,ROW_NUMBER() over(partition BY id) as Row_id_B
,ROW_NUMBER() OVER(PARTITION BY id, price order by price asc) AS [Row_id_price_B]
from TableB as B)

select A.id, A.price, A.Row_A, 
,ResultField=case 
    when A.Row_id_A=C.Row_id_B then C.field 
    when [Row_id_price_A]=[Row_id_price_B] then D.field
    else N'One of many: '+C.field
    end 
from A

outer apply (select top 1 * from B
where 
A.id=B.id
and Row_A=Row_B
) as C

outer apply (select top 1 * from B
where 
A.id=B.id
and Row_A=Row_B
and [Row_id_price_A]=[Row_id_price_B]
) as D

更新。 我添加了样本数据:

CREATE TABLE dbo.TableA(
   id    INTEGER NOT NULL 
  ,price INTEGER NOT NULL
);
INSERT INTO TableA(id,price) VALUES (1,50);
INSERT INTO TableA(id,price) VALUES (2,20);
INSERT INTO TableA(id,price) VALUES (2,30);
INSERT INTO TableA(id,price) VALUES (2,50);
INSERT INTO TableA(id,price) VALUES (4,15);
INSERT INTO TableA(id,price) VALUES (4,5);
INSERT INTO TableA(id,price) VALUES (5,100);
INSERT INTO TableA(id,price) VALUES (5,100);

CREATE TABLE dbo.TableB(
   id    INTEGER NOT NULL 
  ,price INTEGER NOT NULL
  ,field VARCHAR(2) NOT NULL
);
INSERT INTO TableB(id,price,field) VALUES (1,1,'A1');
INSERT INTO TableB(id,price,field) VALUES (2,30,'A2');
INSERT INTO TableB(id,price,field) VALUES (2,50,'A3');
INSERT INTO TableB(id,price,field) VALUES (2,20,'A4');
INSERT INTO TableB(id,price,field) VALUES (5,5,'A5');
INSERT INTO TableB(id,price,field) VALUES (5,100,'A6');
INSERT INTO TableB(id,price,field) VALUES (5,100,'A7');
INSERT INTO TableB(id,price,field) VALUES (6,1,'A8');

听起来像使用两个左连接可以正常工作:

select
 ...
 coalesce (B1.Field, B2.Field) as Field,
 ...

left join TableB B1 on B1.id = TableA.id and B1.price = TableA.price
left join TableB B2 on B2.id = TableA.id

这通常很棘手,因为它可能会导致行重复出现问题,但在您的情况下不应该受到影响。

如果您还需要One of many文本中的One of many ,只需将其添加到coalesce,例如coalesce(B1.Field, 'One of many: ' + B2.Field) - 确保您拥有正确的类型。

编辑:

哦,你关心重复。 在这种情况下,子查询可能是更好的选择:

select
 ...
 coalesce(B1.Field, (select top 1 Field from TableB where id = TableA.id)) as Field
 ...

您可以与Table2进行两次left join (一次用于完全匹配,一次用于一对多匹配)并使用ROW_NUMBER()管理完全匹配的行关联

像这样的东西。 SQL小提琴

样本数据

CREATE TABLE Table1
(
    ID INT NOT NULL,
    Price INT NOT NULL
);

CREATE TABLE Table2
(
    ID INT NOT NULL,
    Price INT NOT NULL,
    Field VARCHAR(20) NOT NULL
);

INSERT INTO Table1 VALUES(1,50),(2,20),(2,30),(2,50),(4,15),(4,5),(5,100),(5,100);
INSERT INTO Table2 VALUES
    (1,1,'A1'),(2,30,'A2'),(2,50,'A3'),(2,20,'A4'),
    (5,5,'A5'),(5,100,'A6'),(5,100,'A7'),(6,1,'A8');

询问

;WITH CT1 AS
(
SELECT *,rn = ROW_NUMBER()OVER(PARTITION BY ID,Price ORDER BY Price)
FROM Table1
), CT2 AS
(
SELECT *,rn = ROW_NUMBER()OVER(PARTITION BY ID,Price ORDER BY Field),
cc = ROW_NUMBER()OVER(PARTITION BY ID ORDER BY Price ASC)
FROM Table2
)
SELECT T1.*,ISNULL(T2.Field,'One of Many: ' + T3.Field) as Field
FROM CT1 T1 
LEFT JOIN CT2 T2 
    ON T1.ID = T2.ID
    AND (T1.Price = T2.Price AND T1.rn = T2.rn)
LEFT JOIN CT2 T3
    ON T1.ID = T3.ID
        AND T3.cc = 1
    ORDER BY T1.Id,T1.Price

产量

| ID | Price | rn |           Field |
|----|-------|----|-----------------|
|  1 |    50 |  1 | One of Many: A1 |
|  2 |    20 |  1 |              A4 |
|  2 |    30 |  1 |              A2 |
|  2 |    50 |  1 |              A3 |
|  4 |     5 |  1 |          (null) |
|  4 |    15 |  1 |          (null) |
|  5 |   100 |  1 |              A6 |
|  5 |   100 |  2 |              A7 |

只需使用此...

BEGIN TRAN
    SELECT A.id, A.price, B.field
    INTO #X
    FROM TableA A
    LEFT JOIN TableB B ON A.id = B.id AND A.price = B.price
    GROUP BY A.id, A.price, B.field

    SELECT X.id, X.price, IIF(X.price = B.price, B.field, 'One Of Many ' + B.field)
    FROM #X X
    LEFT JOIN TableB B ON X.id= B.id
    WHERE X.price = IIF(X.field IS NULL, X.price, B.price)
    GROUP BY X.id, X.price, B.price, B.field
ROLLBACK

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM