根据同一行的两个日期汇总小计列

时间:2019-07-15 20:33:20

标签: sql sql-server

情况:

我有5列

  • id
  • 小计(商品价格)
  • order_date(购买日期)
  • updated_at(如果已退款或其他任何状态更改)
  • 状态

目标

我需要订单日期作为第1列 无论状态是否为第2列,我都需要获取每一天的小计 我需要第三列的退款小计。

示例:

如果5月1日购买了产品,并于5月3日退款了。输出应该像这样

+-------+----------+--------+
| date  | subtotal | refund |
+-------+----------+--------+
| 05-01 |    10.00 |   0.00 |
| 05-02 |    00.00 |   0.00 |
| 05-03 |    00.00 |  10.00 |
+-------+----------+--------+

当行看起来像这样

+-----+----------+------------+------------+----------+
| id  | subtotal | order_date | updated_at |  status  |
+-----+----------+------------+------------+----------+
| 123 |       10 | 2019-05-01 | 2019-05-03 | refunded |
+-----+----------+------------+------------+----------+

查询:

目前我所看到的是这样的: 注意:因此,时区差异会使日期缩短8小时。

;with cte as (
    select id as orderid
        , CAST(dateadd(hour,-8,order_date) as date) as order_date
        , CAST(dateadd(hour,-8,updated_at) as date) as updated_at
        , subtotal
        , status
    from orders
    )

select 
    b.dates
    , sum(a.subtotal_price) as subtotal
    , -- not sure how to aggregate it to get the refunds
from Orders as o
inner join cte as a on orders.id=cte.orderid
inner join (select * from cte where status = ('refund')) as b on o.id=cte.orderid
where dates between '2019-05-01' and '2019-05-31'
group by dates

我需要加入两次吗?希望不是因为我的桌子很大。

2 个答案:

答案 0 :(得分:2)

这看起来像是Calendar Table的工作。在黑暗中有点刺伤,但是:

--Overly simplistic Calendar table
CREATE TABLE dbo.Calendar (CalendarDate date);

WITH N AS(
     SELECT N
     FROM (VALUES(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL))N(N)),
Tally AS(
     SELECT ROW_NUMBER() OVER (ORDER BY (SELECT NULL)) -1 AS I
     FROM N N1, N N2, N N3, N N4, N N5) --Many years of data
INSERT INTO dbo.Calendar
SELECT DATEADD(DAY, T.I, 0)
FROM Tally T;
GO

SELECT C.CalendarDate AS [date],
       CASE C.CalendarDate WHEN V.order_date THEN subtotal ELSE 0 END AS subtotal,
       CASE WHEN C.CalendarDate = V.updated_at AND V.[status] = 'refunded' THEN subtotal ELSE 0.00 END AS subtotal
FROM (VALUES(123,10.00,CONVERT(date,'20190501'),CONVERT(date,'20190503'),'refunded'))V(id,subtotal,order_date,updated_at,status)
     JOIN dbo.Calendar C ON V.order_date <= C.CalendarDate AND V.updated_at >= C.CalendarDate;

GO

DROP TABLE dbo.Calendar;

答案 1 :(得分:1)

考虑按顺序日期的递归CTE加入

WITH dates AS (
    SELECT CONVERT(datetime, '2019-01-01') AS rec_date
    UNION ALL
    SELECT DATEADD(d, 1, CONVERT(datetime, rec_date))
    FROM  dates 
    WHERE rec_date < '2019-12-31'
),    
   cte AS (
    SELECT id AS orderid
        , CAST(dateadd(hour,-8,order_date) AS date) as order_date
        , CAST(dateadd(hour,-8,updated_at) AS date) as updated_at
        , subtotal
        , status
    FROM orders
    )

SELECT rec_date AS date,
       CASE 
          WHEN c.order_date = d.rec_date THEN subtotal
          ELSE 0
       END AS subtotal,

       CASE 
          WHEN c.updated_at = d.rec_date THEN subtotal
          ELSE 0
       END AS refund

FROM cte c
JOIN dates d ON d.rec_date BETWEEN c.order_date AND c.updated_at
WHERE c.status = 'refund'
option (maxrecursion 0)

GO

Rextester demo