完全外部联接问题-几个月没有收入

时间:2018-12-05 12:24:26

标签: sql sql-server join

我遇到的问题是我无法在SQL代码中实现外部联接。我希望没有任何收入的月份在表中显示为“ 0”或“ null”。这应该通过外部联接来完成。

with cte1 as (
select *
from (Values
    (1, 'jan'),
    (2, 'feb'),
    (3, 'mar'),
    (4, 'apr'),
    (5, 'may'),
    (6, 'jun'),
    (7, 'jul'),
    (8, 'aug'),
    (9, 'sep'),
    (10, 'oct'),
    (11, 'nov'),
    (12, 'dec')
) as T(monthnr, maand))
--This part calculates the monthly revenue (maand = month)
select x.regioncode, x.city, x.maand, x.monthlyrevenue, y.totalrevenue
from (
select v.regioncode, city, maand, COALESCE(SUM(oa.amount * pp.price), 0) as monthlyrevenue
from salesregion s
join employee e
on s.regionmgr = e.employeeID
join customer c
on left(c.postalcodehousenumber, 4) between s.pcbegin and s.pcend
join orders o
on o.customerID = c.customerID
join orderamount oa
on oa.orderid = o.orderid
join productprice pp
on pp.productid = oa.productid
join cte1
on month(orderdate) = monthnr
where (o.orderdate > pp.begindate and o.orderdate < pp.enddate) and year(orderdate) = 2014
group by regioncode, city, maand) x
CROSS JOIN
(--This code calculates the total revenue per city.
select city, SUM(oa.amount * pp.price) as totalrevenue
from salesregion s
join employee e
on s.regionmgr = e.employeeID
join customer c
on left(c.postalcodehousenumber, 4) between s.pcbegin and s.pcend
join orders o
on o.customerID = c.customerID
join orderamount oa
on oa.orderid = o.orderid
join productprice pp
on pp.productid = oa.productid
where (o.orderdate > pp.begindate and o.orderdate < pp.enddate) and year(orderdate) = 2014
group by city
)y
where x.city = y.city

我已经知道,外部联接必须在交叉联接部分的顶部实现,因为顶部计算每月收入。 但是,我尝试实施外部联接的任何尝试都会失败,或者会给我带来不好的价值。

我现在得到的东西可以在下图中看到。 图片中从左到右依次是:地区代码,城市,月份,收入,总收入

我想要获得的输出是显示每个城市的所有月份,即使该月没有任何收入。目前,它仅显示当月有收入的月份(我希望它显示城市:Erp,月份:1月,收入:“ 0”或“空”。 Current output

3 个答案:

答案 0 :(得分:0)

这未经测试,但为了简化查询,我做了一些改动。对我来说,交叉连接看起来像是在整个时间段内产生了每个城市的总收入,而不是月度收入,因此我添加了求和函数,这完全消除了对“ y”查询的需要。我可能会误解了您的意图,因此,如果无法产生正确的结果,请尝试更改“分区”语句中的字段。这仅适用于SQL Server 2012及更高版本:

with cte1 as (
select *
from (Values
(1, 'jan'),
(2, 'feb'),
(3, 'mar'),
(4, 'apr'),
(5, 'may'),
(6, 'jun'),
(7, 'jul'),
(8, 'aug'),
(9, 'sep'),
(10, 'oct'),
(11, 'nov'),
(12, 'dec')
) as T(monthnr, maand))
--This part calculates the monthly revenue (maand = month)
select x.regioncode
,x.city
,x.maand
,x.revenue
,sum(x.revenue) over (partition by x.maand) as MonthlyRevenue
from (
select s.regioncode, s.city, cte1.maand, COALESCE(SUM(cr.revenue), 0) as Revenue
from salesregion s
join employee e
on s.regionmgr = e.employeeID
join customer c
on left(c.postalcodehousenumber, 4) between s.pcbegin and s.pcend
cross join cte1
left join
(
select o.customerid
,m.monthnr
,sum(oa.amount * pp.price) as Revenue
from orders o
join orderamount oa
on oa.orderid = o.orderid
join productprice pp
on pp.productid = oa.productid
join cte1 m
on month(o.orderdate) = m.monthnr
where (o.orderdate > pp.begindate and o.orderdate < pp.enddate) and year(orderdate) = 2014
group by o.customerid, m.monthnr
) cr
on c.customerid = cr.customerid
and cte1.monthnr = cr.monthnr
group by s.regioncode, s.city, cte1.maand
) x

答案 1 :(得分:0)

我创建了4个CTE

  • GetMonths-您的CTE1
  • 收入-按城市和地区划分的收入,因此以后的交叉加入需要做的工作更少。
  • GetUniqueCityRegion-如果您想按城市/地区来划分所有月份,那么我需要这个
  • GetUniqueCityRegionMonth-然后将获取每个城市区域的所有月份。

。对我来说,问题是当您说要查看所有月份时,需要按月列出城市区域的信息

由于未提供任何表/样本数据,因此未经测试,并且进行模拟将花费很长时间。

WITH GetMonths as (SELECT *
              FROM (Values
                   (1, 'jan'),(2, 'feb'),(3, 'mar'),(4, 'apr'),(5, 'may'),(6, 'jun'),
                   (7, 'jul'),(8, 'aug'),(9, 'sep'),(10, 'oct'),(11, 'nov'),(12, 'dec')) as T(monthnr, maand)),
Revenue as (SELECT regioncode, city, sum(coalesce(oaamount*pp.price,0)) as RecordRevenue, month(o.Orderdate) as Mo 
            FROM salesregion s
            JOIN employee e
              on s.regionmgr = e.employeeID
            JOIN customer c
              on left(c.postalcodehousenumber, 4) between s.pcbegin and s.pcend
            JOIN orders o
              on o.customerID = c.customerID
            JOIN orderamount oa
              on oa.orderid = o.orderid
            JOIN productprice pp
              on pp.productid = oa.productid
            WHERE o.orderdate > pp.begindate 
              and o.orderdate < pp.enddate) 
              and year(o.orderdate) = 2014
            GROUP BY RegionCode, City),
GetUniqueRegionCity as (SELECT DISTINCT REGIONCODE, City 
         FROM Revenue)
GetUniqueRegionCityMonth as (SELECT RegionCode, City, monthnr, maand
         FROM GetUniqueRegionCity
         CROSS JOIN GetMonths)

--Now get the Total Revenue by City/Region  We left join to revenue from GetUniqueRegionCityMonth to ensure each city/region has all months
    SELECT x.regioncode
         , x.city
         , x.maand
         , x.monthlyrevenue
         , coalesce(sum(RecordRevenue) over (partition by x.city, R.Mo),0) as RevenueCity
         , coalesce(sum(RecordRevenue) over (partition by x.RegionCode, R.Mo),0) RevenueRegion
    FROM GetUniqueRegionCityMonth x
    LEFT JOIN Revenue R
      on R.RegionCode = x.RegionCode
     and R.City = x.City
     and R.Mo = x.MonthNr

答案 2 :(得分:0)

您无需添加交叉申请即可找到TotalRevenue。您只需使用SUM(City) OVER(PARTITION BY City) 我更改并尝试简化您的查询。我相信它可以帮助您。

WITH cte1
AS
(SELECT
        *
    FROM (VALUES(1, 'jan'),
    (2, 'feb'),
    (3, 'mar'),
    (4, 'apr'),
    (5, 'may'),
    (6, 'jun'),
    (7, 'jul'),
    (8, 'aug'),
    (9, 'sep'),
    (10, 'oct'),
    (11, 'nov'),
    (12, 'dec')
    ) AS T (monthnr, maand))
--This part calculates the monthly revenue (maand = month)
SELECT
    x.regioncode
   ,x.city
   ,cte1.maand
   ,x.monthlyrevenue
   ,x.totalrevenue
FROM cte1
LEFT JOIN 
    (SELECT
            s.regioncode
           ,city
           ,MONTH(orderdate) OrderMonth
           ,COALESCE(SUM(oa.amount * pp.price), 0) AS monthlyrevenue
           ,SUM(COALESCE(SUM(oa.amount * pp.price), 0)) OVER (PARTITION BY city) totalrevenue
        FROM salesregion s
        JOIN employee e ON s.regionmgr = e.employeeID
        JOIN customer c ON LEFT(c.postalcodehousenumber, 4) BETWEEN s.pcbegin AND s.pcend
        JOIN orders o ON o.customerID = c.customerID
        JOIN orderamount oa ON oa.orderid = o.orderid
        JOIN productprice pp ON pp.productid = oa.productid
        WHERE (o.orderdate > pp.begindate
        AND o.orderdate < pp.enddate)
        AND YEAR(orderdate) = 2014
        GROUP BY s.regioncode
                ,city
                ,MONTH(orderdate)) x ON CTE1.monthnr = OrderMonth