我在SQL中使用CASE WHENs来根据每个组中不同的计算标准计算一个新列。随着时间的推移,每个帐户的数据都会通过一系列组流动--大部分时间都在增加,但在的情况下,它可以保持不变甚至减少。
以下是我的数据和计算的简化示例:
======================================
| ------ SAMPLE TABLE ------ |
======================================
| ACCT | MONTH | GROUP | VAL1 | VAL2 |
--------------------------------------
| A | Jan | 1 | 2 | 5 |
| A | Feb | 2 | 4 | 9 |
| A | Mar | 3 | 5 | 10 |
| B | Jan | 1 | 10 | 15 |
| B | Feb | 2 | 6 | 9 |
| B | Mar | 2 | 10 | 8 |
| B | Apr | 3 | 8 | 12 |
| B | May | 3 | 6 | 11 |
--------------------------------------
==============================================
| ----- SAMPLE CALCULATIONS ----- |
==============================================
| GROUP = 1: VAL1 + VAL2 |
| GROUP = 2: VAL1 - VAL2 |
| GROUP = 3: Output of most recent GROUP = 2 |
----------------------------------------------我想为所有行计算一个新列(未显示)。注意,GROUP =3的计算标准只是“使用前一组计算输出的最新条目”。虽然可能很容易再次使用组= 2的相同计算公式,但组=3行中的值将有所不同。就账目A及B而言,以下是我所面对的挑战:
帐户A:如何计算组=2中的值,然后将其填充到组= 3中?
帐户B: --这要复杂得多,而且我确实有多个这样的实例。GROUP =3的第一个实例将使用与上面所述A相同的逻辑。但是,对于GROUP = 3的后续实例,它应该返回最新的组=2并复制计算,或者最早的组=3并复制使用A中的方法填充的值(这两种方法仍然应该产生相同的结果)。
希望这是足够清楚的理解。谢谢您的提前,我很高兴回答任何澄清的问题!
发布于 2017-04-17 23:34:37
您应该避免使用“Jan”、“Feb”等字符串来跟踪日期。您的问题需要及时对记录进行排序,但是如果您在月份字段上执行了排序,则它会将其排序为字符串(即'Feb‘、'Jan’、'Mar')。此外,您应该记录确切的日期,而不仅仅是月份,否则您无法保证在多年内准确的时间订购。
尽管如此,有几种不同的方法可以做到这一点,这是我认为非常酷的一种。首先,您需要加入ACCT上的记录,其中左表组为3,右表是最新的非组3数据。此查询:
select
a1.ACCT
, DATEPART(MM, a1.Mnth + ' 1 2017') as Mnth -- see what a pain it is to use strings instead of dates?
, a1.Grp
, a1.Val1
, a1.Val2
, a2.ACCT
, DATEPART(MM, a2.Mnth + ' 1 2017') as Mnth
, a2.Grp
, a2.Val1
, a2.Val2
from #A a1
outer apply (
select top 1 *
from #A
where ACCT = a1.ACCT -- match on the account
and Grp < 3
and a1.Grp = 3 -- I'll explain at the end why we don't actually need this
and DATEPART(MM, Mnth + ' 1 2017') < DATEPART(MM, a1.Mnth + ' 1 2017') -- grab all previous dates
order by DATEPART(MM, Mnth + ' 1 2017') desc -- grab the latest previous date (along with the top command)
) as a2
order by a1.ACCT
, DATEPART(MM, a1.Mnth + ' 1 2017')产生下表:
+ ---- + ---- + --- + ---- + ---- + ---- + ---- + ---- + ---- + ---- +
| ACCT | Mnth | Grp | Val1 | Val2 | ACCT | Mnth | Grp | Val1 | Val2 |
+ ---- + ---- + --- + ---- + ---- + ---- + ---- + ---- + ---- + ---- +
| A | 1 | 1 | 2 | 5 | NULL | NULL | NULL | NULL | NULL |
| A | 2 | 2 | 4 | 9 | NULL | NULL | NULL | NULL | NULL |
| A | 3 | 3 | 5 | 10 | A | 2 | 2 | 4 | 9 |
| B | 1 | 1 | 10 | 15 | NULL | NULL | NULL | NULL | NULL |
| B | 2 | 2 | 6 | 9 | NULL | NULL | NULL | NULL | NULL |
| B | 3 | 2 | 10 | 8 | NULL | NULL | NULL | NULL | NULL |
| B | 4 | 3 | 8 | 12 | B | 3 | 2 | 10 | 8 |
| B | 5 | 3 | 6 | 11 | B | 4 | 3 | 8 | 12 |
+ ---- + ---- + --- + ---- + ---- + ---- + ---- + ---- + ---- + ---- +注意所有的第3组记录是如何在正确的表中有数据的,而组1和2的记录都是空的。让我们利用这个事实来进行计算。修改查询:
select
a1.ACCT
, DATEPART(MM, a1.Mnth + ' 1 2017') as Mnth -- see what a pain it is to use strings instead of dates?
, a1.Grp
, a1.Val1
, a1.Val2
, (case a1.GRP when 1 then a1.Val1 + a1.Val2
when 2 then a1.Val1 - a1.Val2
when 3 then (case a2.Grp when 1 then a2.Val1 + a2.Val2
when 2 then a2.Val1 - a2.Val2
end)
end) as Calculation
from ... -- same as above这给了我们希望的结果:
+ ---- + ---- + --- + ---- + ---- + ----------- +
| ACCT | Mnth | Grp | Val1 | Val2 | Calculation |
+ ---- + ---- + --- + ---- + ---- + ----------- +
| A | 1 | 1 | 2 | 5 | 7 |
| A | 2 | 2 | 4 | 9 | -5 |
| A | 3 | 3 | 5 | 10 | -5 |
| B | 1 | 1 | 10 | 15 | 25 |
| B | 2 | 2 | 6 | 9 | -3 |
| B | 3 | 2 | 10 | 8 | 2 |
| B | 4 | 3 | 8 | 12 | 2 |
| B | 5 | 3 | 6 | 11 | 2 |
+ ---- + ---- + --- + ---- + ---- + ----------- +请注意,我们不需要行and a1.Grp = 3,因为我们编写case语句的方式。去掉那条线,你就会看到我们得到了同样的结果。
希望这能有所帮助!
https://stackoverflow.com/questions/43460455
复制相似问题