我的查询如下
SELECT
LEFT(TimePeriod,6) Period, -- string field with YYYYMMDD
SUM(Value) Value
FROM
f_Trans_GL
WHERE
Account = 228
GROUP BY
TimePeriod
它返回
Period Value
---------------
201412 80
201501 20
201502 30
201506 50
201509 100
201509 100
我想知道相隔1个月的行之间的价值差异。计算为[值期间] - [值期间-1]。
所需的输出是;
Period Value Calculated
-----------------------------------
201412 80 80 - null = 80
201501 20 20 - 80 = -60
201502 30 30 - 20 = 10
201506 50 50 - null = 50
201509 100 (100 + 100) - null = 200
这说明了第二个挑战,因为如果年份发生变化(201501和201412之间的差异为一个月),则需要评估期间。
第三个挑战是重复期(201509),在这种情况下需要评估该期间的总和。
如果可能的话,任何开始的指标都会很棒!
提前致谢
===============================
在我接受了答案后,我根据自己的需要量身定制了一点,最终结果是:
WITH cte
AS (SELECT
ISNULL(CAST(TransactionID AS nvarchar), '_nullTransactionId_') + ISNULL(Description, '_nullDescription_') + CAST(Account AS nvarchar) + Category + Currency + Entity + Scenario AS UID,
LEFT(TimePeriod, 6) Period,
SUM(Value1) Value1,
CAST(LEFT(TimePeriod, 6) + '01' AS date) ord_date
FROM MyTestTable
GROUP BY LEFT(TimePeriod, 6),
TransactionID,
Description,
Account,
Category,
Currency,
Entity,
Scenario,
TimePeriod)
SELECT
a.UID,
a.Period,
--a.Value1,
ISNULL(a.Value1, 0) - ISNULL(b.Value1, 0) Periodic
FROM cte a
LEFT JOIN cte b
ON a.ord_date = DATEADD(MONTH, 1, b.ord_date)
ORDER BY a.UID
我必须为每个UID获取新值(Periodic)。此UID必须在此处确定,因为表中的PK将不起作用。
但问题是,这将返回比我实际在表中开始的更多行。如果我没有按UID添加GROUP BY和ORDER(如上所述),我可以告诉UID和Period的每个组合的第一个结果实际上是正确的,该组合的后续行不是。
我不知道在哪里寻找解决方案,我的猜测是UID就是这里的问题,并且它将以某种方式迭代场......任何方向都值得赞赏。
答案 0 :(得分:1)
正如其他人指出的那样,第一个错误是Group by
你需要Left(timeperiod, 6
)而不是timeperiod
。
对于剩余计算,尝试类似这样的
;WITH cte
AS (SELECT LEFT(timeperiod, 6) Period,
Sum(value) Value,
Cast(LEFT(timeperiod, 6) + '01' AS DATE) ord_date
FROM f_trans_gl
WHERE account = 228
GROUP BY LEFT(timeperiod, 6))
SELECT a.period,
a.value,
a.value - Isnull(b.value, 0)
FROM cte a
LEFT JOIN cte b
ON a.ord_date = Dateadd(month, 1, b.ord_date)
如果您使用SQL SERVER 2012
,则可以使用LAG
分析函数轻松完成此操作
答案 1 :(得分:1)
使用派生表,您可以将数据连接到自身以查找上一期间的行。我已将您的Period
转换为Date
值,以便您可以使用SQL Server的dateadd
函数检查上个月的行:
;WITH cte AS
(
SELECT
LEFT(TimePeriod,6) Period, -- string field with YYYYMMDD
CAST(TimePeriod + '01' AS DATE) PeriodDate
SUM(Value) Value
FROM f_Trans_GL
WHERE Account = 228
GROUP BY LEFT(TimePeriod,6)
)
SELECT c1.Period,
c1.Value,
c1.Value - ISNULL(c2.Value,0) AS Calculation
FROM cte c1
LEFT JOIN cte c2
ON c1.PeriodDate = DATEADD(m,1,c2.PeriodDate)
答案 2 :(得分:0)
没有cte,你也可以尝试这样的事情
SELECT A.Period,A.Value,A.Value-ISNULL(B.Value) Calculated
FROM
(
SELECT LEFT(TimePeriod,6) Period
DATEADD(M,-1,(CONVERT(date,LEFT(TimePeriod,6)+'01'))) PeriodDatePrev,SUM(Value) Value
FROM f_Trans_GL
WHERE Account = 228
GROUP BY LEFT(TimePeriod,6)
) AS A
LEFT OUTER JOIN
(
SELECT LEFT(TimePeriod,6) Period
(CONVERT(date,LEFT(TimePeriod,6)+'01')) PeriodDate,SUM(Value) Value
FROM f_Trans_GL
WHERE Account = 228
GROUP BY LEFT(TimePeriod,6)
) AS B
ON (A.PeriodDatePrev = B.PeriodDate)
ORDER BY 1