使用 Left join , Union 和 Right Join 获得所需的结果

Posted

技术标签:

【中文标题】使用 Left join , Union 和 Right Join 获得所需的结果【英文标题】:Using Left join , Union and Right Join to get a desired result 【发布时间】:2015-01-21 07:31:17 【问题描述】:

我有两个表,分别是“CProduct”和“DProduct”。下面是示例:

C产品:

EffectiveDate   CFund
2014-01-03      0.06
2014-01-03      0.12
2014-01-06      0.11

D产品:

EffectiveDate   DFund
2014-01-03      0.06
2014-01-06      0.12
2014-01-08      0.09

我想得到如下结果:

EffectiveDate  CFund   DFund
2014-01-03     0.18    0.06
2014-01-06     0.11    0.12
2014-01-08     NULL    0.09

我的查询是:

SELECT a.EffectiveDate,a.CFund,a.DFund      
FROM (
SELECT t1.EffectiveDate,Sum(t1.CFund) as CFund ,SUM(t2.DFund) as DFund FROM CProduct t1 
LEFT JOIN DProduct t2 ON t1.EffectiveDate = t2.EffectiveDate Group By t1.EffectiveDate
UNION
SELECT t1.EffectiveDate,SUM(t2.CFund) as CFund ,Sum(t1.DFund) as DFund FROM DProduct t1 
LEFT JOIN CProduct t2 ON t1.EffectiveDate = t2.EffectiveDate Group By t1.EffectiveDate
) a

但我没有得到想要的结果。

【问题讨论】:

两个问题: 1. DProduct中可以有重复的日期吗? 2. CProduct 中可以有 DProduct 中不存在的日期吗? @ZThrosten 是的,这两种情况都可能存在。 【参考方案1】:

应该只是一些子查询和一个完整的外部连接。不知道为什么您认为需要 UNION(尤其是因为它消除了重复行):

SELECT
    COALESCE(t1.EffectiveDate,t2.EffectiveDate) as EffectiveDate,
    t1.Total,
    t2.Total
FROM
    (select EffectiveDate,SUM(CFund)
    from CProduct
    group by EffectiveDate) as t1(EffectiveDate,Total)
        full outer join
    (select EffectiveDate,SUM(DFund)
    from DProduct
    group by EffectiveDate) as t2(EffectiveDate,Total)
        on
            t1.EffectiveDate = t2.EffectiveDate

【讨论】:

有什么办法不使用COALESCE功能?? @vivek 为什么要避免合并? @Taemyr 因为我需要将它与 vba (MS-ACCESS) 一起使用,而这是在 vba 中不起作用的 sql 函数。 @vivek - 一个问题最多允许有 5 个标签,而您只使用了 3 个标签,但您认为应用 2 个 SQL Server 标签比包含 ms-access 更重要? @vivek ***.com/questions/247858/…【参考方案2】:

这会得到您想要的结果 - 不太清楚为什么其他回答者认为 join 和 COALESCE 如此重要:

SELECT a.EffectiveDate, SUM(a.CFund) AS CFund, SUM(a.DFund) AS DFund
FROM (
    SELECT c.EffectiveDate, c.CFund, NULL AS DFund
    FROM CProduct c
    UNION ALL
    SELECT d.EffectiveDate, NULL AS CFund, d.DFund
    FROM DProduct d
) a
GROUP BY a.EffectiveDate
ORDER BY a.EffectiveDate

在 SQL Fiddle 中,针对 SQLite(我还没有检查,但 Access 也应该没问题):http://sqlfiddle.com/#!7/80158/1

【讨论】:

【参考方案3】:

您正在将相反的外部联接与 UNION 一起使用,以模拟 FULL OUTER JOIN。这没关系,但不是必需的,因为 SQL Server 2008(和 2005 也一样)具有完整的外部连接。

但是,您的问题更为根本。您正在加入来自 CProduct 和 DProduct 的所有记录,然后建立总和。所以说日期 2014-01-01 在 CProduct 中有两条记录,在 DProduct 中有三条记录。您的联接为您提供了六条记录 (2x3)。然后你建立你的总和,从而考虑 DProduct 值的两倍和 CProduct 条目的三倍。

话虽如此,您不想按日期将每个 CProduct 记录与每个 DProduct 记录连接起来。您想加入每个日期的总和。 IE。先聚合,再加入。

select 
  coalesce(c.effectivedate, d.effectivedate) as effectivedate,
  coalesce(c.sumfund,0) as cfund, 
  coalesce(d.sumfund,0) as dfund
from 
  (select effectivedate, sum(cfund) as sumfund from cproduct group by effectivedate) c
full outer join 
  (select effectivedate, sum(dfund) as sumfund from dproduct group by effectivedate) d
on c.effectivedate = d.effectivedate;

没有完全外连接:

select 
  c.effectivedate,
  c.sumfund as cfund, 
  d.sumfund as dfund
from 
  (select effectivedate, sum(cfund) as sumfund from cproduct group by effectivedate) c
left outer join 
  (select effectivedate, sum(dfund) as sumfund from dproduct group by effectivedate) d
on c.effectivedate = d.effectivedate
union
select 
  d.effectivedate,
  c.sumfund as cfund, 
  d.sumfund as dfund
from 
  (select effectivedate, sum(cfund) as sumfund from cproduct group by effectivedate) c
right outer join 
  (select effectivedate, sum(dfund) as sumfund from dproduct group by effectivedate) d
on c.effectivedate = d.effectivedate;

【讨论】:

当日期不存在条目时,OP 请求 NULL,因此最后两个合并函数是 uncesarry。 @Thorsten 能否请您提供与上述查询等效的工作 vba 查询,即使在将 COALESCE 替换为 Nz 之后,它也会在 vba 中的 From 子句中给出语法错误。不知道为什么。但在 sql 中工作正常。 @vivek:VBA?微软访问?您已标记您的请求 SQL-Server 2008。我认为 MS-Access 不支持完全外连接,因此我添加了一个模仿查询(尽管我认为您应该能够使用给定的信息自己构建它)。跨度> @Thorsten 是的,这是我的错误。我为此道歉。我已经纠正了。我现在正在尝试。 @ThorstenKettner 我不太确定“左外连接”是否适用于 vba。【参考方案4】:

使用 coalesce 或类似方法是正确的解决方案。

但是,在您的情况下,可以避免它,想法是在单独的子查询中获取日期,然后通过左连接获得总和。

SELECT
Date.EffectiveDate as EffectiveDate,
t1.Total as t1,
t2.Total as t2
FROM
(select distinct EffectiveDate from CProduct
 union
 select distinct EffectiveDate from DProduct
) as Date
left join
(select EffectiveDate,SUM(CFund)
from CProduct
group by EffectiveDate) as t1(EffectiveDate,Total)
on Date.EffectiveDate=t1.EffectiveDate
left join
(select EffectiveDate,SUM(DFund)
from DProduct
group by EffectiveDate) as t2(EffectiveDate,Total)
    on
        Date.EffectiveDate = t2.EffectiveDate

【讨论】:

即使在用 Nz 替换 COALESCE 后,您能否提供与上述查询等效的工作 vba 查询,它在 vba 中的 From 子句中给出语法错误。不知道为什么。但在 sql 中工作正常。 @vivek 此查询不使用 COALESCE。但是请参阅我在 Damien 的回答中的评论。【参考方案5】:

SELECT E121.EffectiveDate,sum(E12.Cfund) AS CFUND,AVG(e121.Dfund) AS DFUND FROM E121 LEFT JOIN E12 ON E121.EffectiveDate=E12.EffectiveDate GROUP BY E121.EffectiveDate

【讨论】:

以上是关于使用 Left join , Union 和 Right Join 获得所需的结果的主要内容,如果未能解决你的问题,请参考以下文章

SQLite3 使用 LEFT JOIN 和 UNION 模拟 RIGHT OUTER JOIN

关于SQL 查询效率问题 left join 改成 inner join union

MYSQL FULL OUTER JOIN - 使用 LEFT-UNION-LEFT JOIN 时的所有 NULL 结果

SQL 里LEFT JOIN 和UNION 怎么一同使用?

mysql中left join和union有啥区别?

left join ,right join ,inner join,outer join,union all,union有啥区别?怎么用?