【问题标题】:How can I write this query as a full join instead of a union left/right join?如何将此查询编写为完全联接而不是联合左/右联接?
【发布时间】:2011-08-11 03:45:29
【问题描述】:

这是代码,显示了输入和所需的输出。

基本上,我正在尝试自我加入,以将我的经纪人声明的结果与我的内部记录相匹配。所以左边的一组列是经纪人的名单,右边是我的名单。如果经纪人有头寸,而我没有,右边的空值。如果我有头寸而经纪人没有头寸,则左侧为 NULL。

left join + right join + union 完全符合我的要求。似乎应该有一些巫术来允许完全加入而无需两次选择即可获得它,但我无法弄清楚。

drop table MatchPositions
go

create table MatchPositions
( 
    mt_source varchar (10),
    mt_symbol varchar (10),
    mt_qty float,
    mt_price float
)

go

insert into MatchPositions values ('BROKER', 'IBM', 100, 50.25)
insert into MatchPositions values ('BROKER', 'MSFT', 75, 30)
insert into MatchPositions values ('BROKER', 'GOOG', 25, 500)
insert into MatchPositions values ('BROKER', 'SPY', 200, 113)

insert into MatchPositions values ('MODEL', 'MSFT', 75, 30)
insert into MatchPositions values ('MODEL', 'GOOG', 25, 500)
insert into MatchPositions values ('MODEL', 'GLD', 300, 150)

go

select * from MatchPositions b
left join MatchPositions m on b.mt_symbol = m.mt_symbol and m.mt_source = 'MODEL'
where b.mt_source = 'BROKER'
union

select * from MatchPositions b
right join MatchPositions m on b.mt_symbol = m.mt_symbol and b.mt_source = 'BROKER'
where m.mt_source = 'MODEL'

这是预期的输出:

mt_source  mt_symbol  mt_qty                 mt_price               mt_source  mt_symbol  mt_qty                 mt_price
---------- ---------- ---------------------- ---------------------- ---------- ---------- ---------------------- ----------------------
NULL       NULL       NULL                   NULL                   MODEL      GLD        300                    150
BROKER     GOOG       25                     500                    MODEL      GOOG       25                     500
BROKER     IBM        100                    50.25                  NULL       NULL       NULL                   NULL
BROKER     MSFT       75                     30                     MODEL      MSFT       75                     30
BROKER     SPY        200                    113                    NULL       NULL       NULL                   NULL

【问题讨论】:

  • 你用的是什么版本的sql?

标签: sql join union


【解决方案1】:

如果您的 RDBMS 支持 FULL JOIN(也称为 FULL OUTER JOIN):

SELECT *
FROM (SELECT * FROM MatchPositions WHERE mt_source = 'BROKER') b
FULL
JOIN (SELECT * FROM MatchPositions WHERE mt_source = 'MODEL' ) m
  ON b.mt_symbol = m.mt_symbol

此解决方案与 Martin 的解决方案基本相同,只是使用了不同的语法,如果您的 RDBMS 不支持 CTE,这可能会有所帮助。

【讨论】:

  • 返回 4 行而不是 5 行以及 OP 的数据(它不包括所需输出顶部的 NULL 之一)
  • 讨厌把这个给你,但它现在返回 9 行!
  • @Martin。再次修复,再次感谢。老实说,我试图避免发布这个最终解决方案。我知道它会起作用,只是想找到一些不那么明显的东西。我猜这还不够成熟。
【解决方案2】:

试试这个:

select *
from      MatchPositions broker
full join MatchPositions model  on model.mt_symbol =  broker.mt_symbol
                               and model.mt_source <> broker.mt_source
where ( broker.mt_source = 'BROKER' or broker.MT_SOURCE is null )
  and ( model.mt_source  = 'MODEL'  or model.MT_SOURCE is null )

从第一个逻辑源表中,您需要代理行或缺失行。

从第二个逻辑源表中,您需要模型行或缺失行。

【讨论】:

    【解决方案3】:
    SELECT *
    FROM MatchPositions b
      FULL JOIN MatchPositions m ON b.mt_symbol = m.mt_symbol
                                AND b.mt_source = 'BROKER'
                                AND m.mt_source = 'MODEL'
    

    这会在外部连接之前将表过滤为“BROKER”和“MODEL”部分。

    【讨论】:

    【解决方案4】:

    可能使用 isnull 函数:

    SELECT *
    FROM MatchPositions b
      FULL JOIN MatchPositions m on b.mt_symbol = m.mt_symbol
                                and b.mt_source != m.mt_source
    WHERE isnull(b.mt_source, 'BROKER') = 'BROKER'
      and isnull(m.mt_source, 'MODEL') = 'MODEL'
    

    【讨论】:

    • 几乎是对的,但是将mt_source 列包装在一个函数中会否定索引的任何可能使用。请参阅下面的更好方法。
    【解决方案5】:
    ;WITH T1 AS
    (
    SELECT *
    FROM MatchPositions 
    WHERE mt_source = 'BROKER'
    ), T2 AS
    (
    SELECT *
    FROM MatchPositions 
    WHERE mt_source = 'MODEL'
    )
    SELECT *
    FROM T1 FULL JOIN T2 ON T1.mt_symbol = T2.mt_symbol
    

    【讨论】:

    • 当然是 CTE! (捂脸)。谢谢,这也解决了更一般的情况(我没有发布),其中表有点复杂,并且在存在 NULL 的情况下将内容放在“where”与“join”中会变得很冒险。您的解决方案解决了所有这些问题。
    猜你喜欢
    • 1970-01-01
    • 2016-12-13
    • 1970-01-01
    • 1970-01-01
    • 2011-09-01
    • 1970-01-01
    • 2023-03-11
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多