如何按日期限制完全加入

How to limit a full join by date

我们的数据库在 SQL Server 2014 上。我遇到了与 完全相同的问题,很高兴找到答案。所以我设置了我的查询:

select distinct 
    coalesce (a.year, b.year+1) [Year]
  , coalesce(a.Month, b.Month) [Month]
  , coalesce(a.account, b.account) [Account]
  , case when a.sales > 0
        then a.sales
        else 0 end [Sales MTD]
  , case when b.sales > 0
        then b.sales
        else 0 end [Sales Previous Year]
  , (case when b.sales!= 0
        then cast((case when a.sales > 0
                then a.sales
                else 0 end-b.sales)/b.sales*100 as decimal(10,1))
        else 0 end) [% Difference]
  , sum(a.sales) over (Partition by a.account, a.year order by a.month) [Account Sales YTD]
from yourtable a
      full join yourtable b 
            on  a.account = b.account
            and a.month = b.month
            and a.year = b.year+1

输出为我提供了 2022 年尚未发生的几个月的结果(2023 年也开始)。 https://dbfiddle.uk/?rdbms=sqlserver_2014&fiddle=9a2c29f1af08f525a1acee16b0efa2fd

我尝试将 and b.[year]+1<=year(getdate()) 添加到我的连接过滤器中,但这似乎根本不会影响输出。我还尝试写了一个 where 子句,结果是一个让我头晕目眩的案例。

如何防止未来日期出现在最终结果中? 奖励问题:我能否让我的 YTD 计算接受 0 作为因销售历史记录而添加的任何行的值?

如果我没理解错的话,你需要一个左外连接,因为你关心的是一个 table 但不是两个都有记录。

在执行完全连接之前缩小相关行的列表范围。

with A as (
    select *
    from tableA
    where ...
), B as (
    select *
    from tableB
    where ...
)
select * from A full outer join B on ...

您也可以内联执行此操作:

select *
from
    (select * from tableA where ...) as A
    full outer join
    (select * from tableB where ...) as B

编辑: 如果您“pre-filter”相关日期内的数据,您以后不需要进行笨拙的联合检查:

with A as (
    select year, month, account, sales
    from yourtable
    -- if there's no future data then this whole cte may be unnecessary
    where year < year(getdate())
       or year = year(getdate()) and month <= month(getdate())
), B as (
    select year + 1 as year, month, account, sales
    from yourtable 
    where year < year(getdate()) - 1
       or year = year(getdate()) - 1 and month <= month(getdate())
)
select
    coalesce(a.year, b.year) [Year]
  , coalesce(a.Month, b.Month) [Month]
  , coalesce(a.account, b.account) [Account]
  , sum(a.sales) over (Partition by a.account, a.year order by a.month) [Account Sales YTD]  
from A full outer join B
    on  a.account = b.account
    and a.month = b.month
    and a.year = b.year
order by 1, 2

https://dbfiddle.uk/?rdbms=sqlserver_2014&fiddle=26c30b190d475d8679f2253a3c428f1f

添加 WHERE 子句

... 
where datefromparts(coalesce(a.year, b.year+1), coalesce(a.Month, b.Month), 1) <= cast(getdate() as date)