我有一个查询。这是重复的。基本上,我收集了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
答案 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