使用SQL Server或Vertica将按日期范围的记录转换为按日/月的记录

时间:2018-11-15 19:44:02

标签: sql sql-server tsql tableau vertica

我可以使用SQL Server或Vertica作为数据库,使用Tableau作为报告工具。在这些媒介中的任何一种解决方案都是有帮助的。

数据资源: 我有一个包含100条记录的表(userActivity),其结构为:User,StartDate,EndDate

需要: 我有兴趣按日期和月份准备显示“活动总天数”的报告,这意味着,如果User1的范围从“ 20180101”到“ 20180331”,则他们将在1月,2月和3月的每一天贡献一天,或31如果按月汇总则为28天和31天。

目标: 最终,我将所有用户的总活动天数汇总为输出,以实现每天/每月的总计。

此报告将涉及永久性,所以我希望解决方案不要按日/月对CASE / IF-THEN语句进行硬编码。

谢谢!

3 个答案:

答案 0 :(得分:2)

尽管递归CTE是此方案的理想选择,但可以单独使用tableau进行处理。假设您拥有这些数据,下面是生成视图所需的步骤。

enter image description here

  1. 创建具有所有预期天数的参考表。即使您需要涵盖从01/01/2018到01/01/2043的25年,这仍然少于1万行。

enter image description here

您需要两列日期完全相同的表,因为Tableau不允许同一列上有多个连接条件。

  1. 使用以下条件在参考日历和数据之间创建内部联接。 enter image description here

  2. 构建视图

    enter image description here

答案 1 :(得分:2)

使用Vertica-它具有TIMESERIES子句-无需递归。

我将尝试以下操作-并检查通用表表达式的中间结果,以了解其工作原理。

WITH 
-- two test rows ....
input(uid,start_dt,end_dt) AS (
            SELECT 1,DATE '2018-01-01', DATE '2018-03-31'
  UNION ALL SELECT 2,DATE '2018-02-01', DATE '2018-04-01'
)
,
-- set the stage for Vertica's TIMESERIES clause
-- note: TIMESERIES relies on timestamps ...
limits(uid,lim_dt,qty) AS (
  SELECT
    uid
  , start_dt::TIMESTAMP
  , 1
  FROM input
  UNION ALL
  SELECT
    uid
  , end_dt::TIMESTAMP
  , 1
  FROM input
)
,
-- apply the Vertica TIMESERIES clause
counters AS (
  SELECT
    uid
  , act_dt
  , TS_FIRST_VALUE(qty) AS qty
  FROM limits
  TIMESERIES act_dt AS '1 DAY' OVER(PARTITION BY uid ORDER BY lim_dt)
)
SELECT
  uid
, MONTH(act_dt) AS activity_month
, SUM(qty)
FROM counters
GROUP BY 1,2;
-- out  uid | activity_month | sum 
-- out -----+----------------+-----
-- out    1 |              1 |  31
-- out    1 |              2 |  28
-- out    1 |              3 |  31
-- out    2 |              2 |  28
-- out    2 |              3 |  31
-- out    2 |              4 |   1
-- out (6 rows)
-- out 
-- out time: first fetch (6 rows): 120.515 ms. all rows formatted: 120.627 ms

答案 2 :(得分:0)

解决方案:

WITH base AS (
  SELECT
     User       AS u
    ,StartDate  AS s
    ,EndDate    AS e
    ,DATEDIFF(
      dd,
      StartDate,
      EndDate
      )+1       AS d
  FROM  userActivity
  ),
recurse AS (
  SELECT    u, s, e, d, x=(d-1)
    FROM    base
    UNION ALL
    SELECT  u, s, e, d, x-1 AS x
    FROM    recurse
    WHERE   x>0
  )
SELECT      u, DATEADD(dd, x, s) AS recordperday
FROM        recurse
ORDER BY    u, recordperday
--Extends SQL Server's recursion limit
OPTION (MAXRECURSION 500)