常见sql查询的迭代日期

时间:2018-02-07 17:57:35

标签: sql-server

我有一个查询。这是重复的。基本上,我收集了13个月的月度数据。

常见的查询基本上是这样的:

true

唯一改变的是日期:

    SELECT
        SUM(Timecards.Work_Amt_USD) AS billableDollars,
        SUM(Timecards.Work_Hours) AS billableHours,
        Entities.Timekeeper_Id AS Timekeeper_Id
    FROM dim.Elmts_Ent_Entity AS Entities
    INNER JOIN fact.Rec_Work_Timecard AS Timecards
        ON Entities.id = Timecards.Working_Timekeeper_Id
    WHERE Date_Worked_Effective >= DATEADD(MONTH, -1, DATEADD(DAY, 1 - DAY(GETDATE()), GETDATE()))
        AND Date_Worked_Effective < DATEADD(MONTH, -1 + 1, DATEADD(DAY, 1 - DAY(GETDATE()), GETDATE()))
        AND (Work_Amt_USD <> 0
        OR Work_Hours <> 0)
    GROUP BY Timekeeper_Id, Date_Worked_Effective

这将减去一组月份的月数[-1到-13]。

目前,这个sql被复制了13次。我想反复迭代13次。

我查看了常用的表格表达式,但它并不清楚如何传递月份变量。这样做的最佳方法是制作存储过程或函数吗?

我打电话给:

WHERE Date_Worked_Effective >= DATEADD(MONTH, ***CHANGE HERE -1***, DATEADD(DAY, 1 - DAY(GETDATE()), GETDATE()))
        AND Date_Worked_Effective < DATEADD(MONTH, ****CHANGE HERE -1*** + 1, DATEADD(DAY, 1 - DAY(GETDATE()), GETDATE()))

这里完全凌乱的查询: query

3 个答案:

答案 0 :(得分:2)

我是否正确,以下产生基本上你需要的行形式?

WITH time_data AS
(
    SELECT
        Entities.Timekeeper_Id
        ,Timecards.Work_Amt_USD
        ,Timecards.Work_Hours
        ,DATEDIFF(YEAR, Date_Worked_Effective, GETDATE()) AS years_prior
        ,DATEDIFF(MONTH, Date_Worked_Effective, GETDATE()) AS months_prior

    FROM 
        dim.Elmts_Ent_Entity AS Entities

    INNER JOIN 
        fact.Rec_Work_Timecard AS Timecards
        ON (Entities.id = Timecards.Working_Timekeeper_Id)
)
SELECT
    Timekeeper_Id
    ,months_prior
    ,SUM(Work_Amt_USD) AS billable_dollars
    ,SUM(Work_Hours) AS billable_hours

FROM
    time_data

GROUP BY 
    Timekeeper_Id, years_prior, months_prior

ORDER BY
    Timekeeper_Id, years_prior, months_prior

如果您需要将每个月的摘要翻译成相应的列,请过滤(例如)months_prior BETWEEN 1 AND 12,然后使用PIVOT工具。

当然,您链接的完整查询是狗的晚餐!

编辑:来自以下评论。

这应该让您了解如何旋转结果并将它们组合在一起。由于它是重复性的工作,我将让您将列交错到您可能更喜欢的最终形式!

再一次,我在没有测试的情况下将其写在袖口上。

WITH time_data AS
(
    SELECT
        Entities.Timekeeper_Id
        ,ISNULL(Timecards.Work_Amt_USD, 0) AS Work_Amt_USD
        ,ISNULL(Timecards.Work_Hours, 0) AS Work_Hours
        ,DATEDIFF(YEAR, Date_Worked_Effective, GETDATE()) AS years_prior
        ,DATEDIFF(MONTH, Date_Worked_Effective, GETDATE()) AS months_prior

    FROM 
        dim.Elmts_Ent_Entity AS Entities

    INNER JOIN 
        fact.Rec_Work_Timecard AS Timecards
        ON (Entities.id = Timecards.Working_Timekeeper_Id)
)

,timekeeper_ids AS
(
    SELECT Timekeeper_Id 
    FROM time_data 
    GROUP BY Timekeeper_Id
)

,monthly_data_source AS
(
    SELECT
        Timekeeper_Id
        ,months_prior
        ,SUM(Work_Amt_USD) AS billable_dollars
        ,SUM(Work_Hours) AS billable_hours
    FROM time_data
    WHERE months_prior BETWEEN 1 AND 13
    GROUP BY Timekeeper_Id, months_prior
)
,yearly_data_source AS
(
    SELECT
        Timekeeper_Id
        ,years_prior
        ,SUM(Work_Amt_USD) AS billable_dollars
        ,SUM(Work_Hours) AS billable_hours
    FROM time_data
    WHERE years_prior BETWEEN 0 AND 4
    GROUP BY Timekeeper_Id, years_prior
)
,rolling_twelve_data_source AS
(
    SELECT
        Timekeeper_Id
        --,(months_prior / 12) AS rolling_twelve_prior
        ,SUM(Work_Amt_USD) AS billable_dollars
        ,SUM(Work_Hours) AS billable_hours
    FROM time_data
    WHERE (months_prior / 12) = 0 --the last 12 months
    GROUP BY Timekeeper_Id --, (months_prior / 12)
)   

,pivoted_monthly_dollars AS
(
    SELECT 
         Timekeeper_Id
        ,[1] AS m01_dollars
        ,[2] AS m02_dollars
        ,[3] AS m03_dollars
        ,[4] AS m04_dollars
        ,[5] AS m05_dollars
        ,[6] AS m06_dollars
        ,[7] AS m07_dollars
        ,[8] AS m08_dollars
        ,[9] AS m09_dollars
        ,[10] AS m10_dollars
        ,[11] AS m11_dollars
        ,[12] AS m12_dollars
        ,[13] AS m13_dollars
    FROM (SELECT Timekeeper_Id, months_prior, billable_dollars FROM monthly_data_source) AS mds
    PIVOT (
        MAX(billable_dollars)
        FOR months_prior IN ([1],[2],[3],[4],[5],[6],[7],[8],[9],[10],[11],[12],[13])
    ) AS pivot_result
)
,pivoted_monthly_hours AS
(
    SELECT
         Timekeeper_Id
        ,[1] AS m01_hours
        ,[2] AS m02_hours
        ,[3] AS m03_hours
        ,[4] AS m04_hours
        ,[5] AS m05_hours
        ,[6] AS m06_hours
        ,[7] AS m07_hours
        ,[8] AS m08_hours
        ,[9] AS m09_hours
        ,[10] AS m10_hours
        ,[11] AS m11_hours
        ,[12] AS m12_hours
        ,[13] AS m13_hours
    FROM (SELECT Timekeeper_Id, months_prior, billable_hours FROM monthly_data_source) AS mds
    PIVOT (
        MAX(billable_hours)
        FOR months_prior IN ([1],[2],[3],[4],[5],[6],[7],[8],[9],[10],[11],[12],[13])
    ) AS pivot_result
)

,pivoted_yearly_dollars AS
(
    SELECT
         Timekeeper_Id
        ,[0] AS y00_dollars
        ,[1] AS y01_dollars
        ,[2] AS y02_dollars
        ,[3] AS y03_dollars
        ,[4] AS y04_dollars
    FROM (SELECT Timekeeper_Id, years_prior, billable_dollars FROM yearly_data_source) AS yds
    PIVOT (
        MAX(billable_dollars)
        FOR years_prior IN ([0],[1],[2],[3],[4])
    ) AS pivot_result
)
,pivoted_yearly_hours AS
(
    SELECT 
         Timekeeper_Id
        ,[0] AS y00_hours
        ,[1] AS y01_hours
        ,[2] AS y02_hours
        ,[3] AS y03_hours
        ,[4] AS y04_hours
    FROM (SELECT Timekeeper_Id, years_prior, billable_hours FROM yearly_data_source) AS yds
    PIVOT (
        MAX(billable_hours)
        FOR years_prior IN ([0],[1],[2],[3],[4])
    ) AS pivot_result
)

SELECT
    tids.Timekeeper_Id
    ,pmd.*
    ,pmh.*
    ,pyd.*
    ,pyh.*
    ,rtds.billable_dollars AS rtds_billable_dollars
    ,rtds.billable_hours AS rtds_billable_hours

FROM
    timekeeper_ids AS tids

LEFT JOIN
    pivoted_monthly_dollars AS pmd
    ON (pmd.Timekeeper_Id = tids.Timekeeper_Id)

LEFT JOIN
    pivoted_monthly_hours AS pmh
    ON (pmh.Timekeeper_Id = tids.Timekeeper_Id)

LEFT JOIN
    pivoted_yearly_dollars AS pyd
    ON (pyd.Timekeeper_Id = tids.Timekeeper_Id)

LEFT JOIN
    pivoted_yearly_hours AS pyh
    ON (pyh.Timekeeper_Id = tids.Timekeeper_Id)

LEFT JOIN
    rolling_twelve_data_source AS rtds
    ON (rtds.Timekeeper_Id = tids.Timekeeper_Id)

ORDER BY
    tids.Timekeeper_Id

答案 1 :(得分:1)

这是TSQL中的一个简单循环,它从SSMS等交互式窗口运行。不确定您是否确实需要单个结果集,或者您是否需要参数化查询,而不是可以在另一个应用程序中使用。

@DECLARE @N INTEGER = 1;

WHILE @N <= 13
BEGIN
    SELECT
        SUM(Timecards.Work_Amt_USD) AS billableDollars,
        SUM(Timecards.Work_Hours) AS billableHours,
        Entities.Timekeeper_Id AS Timekeeper_Id
    FROM dim.Elmts_Ent_Entity AS Entities
    INNER JOIN fact.Rec_Work_Timecard AS Timecards
        ON Entities.id = Timecards.Working_Timekeeper_Id
    WHERE Date_Worked_Effective >= DATEADD(MONTH, -@N, DATEADD(DAY, 1 - DAY(GETDATE()), GETDATE()))
        AND Date_Worked_Effective < DATEADD(MONTH, -@N + 1, DATEADD(DAY, 1 - DAY(GETDATE()), GETDATE()))
        AND (Work_Amt_USD <> 0 OR Work_Hours <> 0)
    GROUP BY Timekeeper_Id, Date_Worked_Effective;
    SET @N = @N + 1;
END

对于单个结果集,您可以执行以下操作:

with mnths as (
    select offset from (values (1), (2), (3), (4), (5), (6), (7), (8), (9), (10), (11), (12), (13)) n(offset)
)
select q.*
from mnths cross apply (
    SELECT
        SUM(Timecards.Work_Amt_USD) AS billableDollars,
        SUM(Timecards.Work_Hours) AS billableHours,
        Entities.Timekeeper_Id AS Timekeeper_Id
    FROM dim.Elmts_Ent_Entity AS Entities
    INNER JOIN fact.Rec_Work_Timecard AS Timecards
        ON Entities.id = Timecards.Working_Timekeeper_Id
    WHERE Date_Worked_Effective >= DATEADD(MONTH, -mnths.offset, DATEADD(DAY, 1 - DAY(GETDATE()), GETDATE()))
        AND Date_Worked_Effective < DATEADD(MONTH, -mnths.offset + 1, DATEADD(DAY, 1 - DAY(GETDATE()), GETDATE()))
        AND (Work_Amt_USD <> 0 OR Work_Hours <> 0)
    GROUP BY Timekeeper_Id, Date_Worked_Effective
) q;

这里的一个明显优势是你几乎可以放弃查询。因为查询是“模块化的”,所以您不必担心通过连接和组逻辑进行推理,以确保将所有结果连接在一起。

答案 2 :(得分:1)

如果您的目标是拥有一个结果集,那么您可以使用CTE创建一组索引,并在主查询中加入它们。您可以为索引提供值列表,也可以使用递归CTE生成变量lit。

要确保获得相同的行,如果您有不同的查询,请将“索引”值添加到Group By。这可能不是完全必要的,因为我无法想象一个具有不同索引的相同生效日期出现的怪癖。

DECLARE @IndexCount INT = 13;

WITH indexes AS (
  SELECT -1 [IndexValue]
  UNION ALL
  SELECT [IndexValue] - 1
  FROM indexes
  WHERE IndexValue * -1 <= @IndexCount
)
SELECT
  SUM(Timecards.Work_Amt_USD) AS billableDollars,
  SUM(Timecards.Work_Hours) AS billableHours,
  Entities.Timekeeper_Id AS Timekeeper_Id
FROM dim.Elmts_Ent_Entity AS Entities
CROSS JOIN indexes 
INNER JOIN fact.Rec_Work_Timecard AS Timecards
  ON Entities.id = Timecards.Working_Timekeeper_Id
WHERE Date_Worked_Effective >= DATEADD(MONTH, indexes.IndexValue, DATEADD(DAY, 1 - DAY(GETDATE()), GETDATE()))
  AND Date_Worked_Effective < DATEADD(MONTH, indexes.IndexValue + 1, DATEADD(DAY, 1 - DAY(GETDATE()), GETDATE()))
  AND (Work_Amt_USD <> 0 OR Work_Hours <> 0)
GROUP BY Timekeeper_Id, Date_Worked_Effective, indexes.IndexValue