我已经看过很多类似的问题,但没有什么能够解决我的特殊问题。
我有一个表格,为每个帐户存储多个位置。更改存储为增量。因此,例如在第1天以下......
AC_ID | POS_ID | ASAT | VAL
1 | 1 | 2016-01-01 | 100
1 | 2 | 2016-01-01 | 200
2016年01月1日AC_ID
1的总值为300.第二天它可能会更新为...
AC_ID | POS_ID | ASAT | VAL
1 | 1 | 2016-01-01 | 100
1 | 2 | 2016-01-01 | 200
1 | 2 | 2016-01-02 | 250
现在AC_ID
1的总值为350.这是因为POS_ID
2的新记录会覆盖之前的记录,但POS_ID
1的值未更改。为了删除POS_ID
1,表格将更改为......
AC_ID | POS_ID | ASAT | VAL
1 | 1 | 2016-01-01 | 100
1 | 2 | 2016-01-01 | 200
1 | 2 | 2016-01-02 | 250
1 | 1 | 2016-01-03 | 0
现在价值在第3天变为250。
我可以使用像这样的子查询计算任何给定日期的值
SELECT SUM(VAL) FROM POSITION P1
WHERE P1.ASAT =
(SELECT MAX(P2.ASAT) FROM POSITION P2
WHERE P1.AC_ID = P2.AC_ID
AND P1.POS_ID = P2.POS_ID
AND P2.DATE <= [CHOSEN DATE])
我现在要做的是编写一个查询,它会为每个AC_ID
的每个ASAT
提供总价值。如果不是delta存储机制,我可以使用
SELECT AC_ID, ASAT, SUM(VAL) FROM POSITION
GROUP BY AC_ID, ASAT
ORDER BY ASAT DESC
我正在寻找的东西将实现上述目标,但考虑到桌面上的联接。如果我使用上述内容,那么我只会获得ASAT
日期发生变化的所有内容的总计,而不是所有未更改的现有值。
在上面的示例中,应该等同于
的结果集AC_ID | ASAT | SUM(VAL)
1 | 2016-01-01 | 300
1 | 2016-01-02 | 350
1 | 2016-01-03 | 250
这是数据与输出的另一个例子
AC_ID | POS_ID | ASAT | VAL
1 | 1 | 2016-01-01 | 100
1 | 2 | 2016-01-01 | 200
1 | 2 | 2016-01-02 | 250
1 | 1 | 2016-01-03 | 0
2 | 1 | 2016-01-02 | 500
3 | 7 | 2016-01-02 | 1000
3 | 7 | 2016-01-03 | 1000
3 | 12 | 2016-01-03 | 5000
2 | 1 | 2016-01-04 | 750
结果
AC_ID | ASAT | SUM(VAL)
1 | 2016-01-01 | 300
1 | 2016-01-02 | 350
1 | 2016-01-03 | 250
2 | 2016-01-02 | 500
2 | 2016-01-04 | 750
3 | 2016-01-02 | 1000
3 | 2016-01-03 | 6000
我改变了它的工作方式
虽然下面的答案奏效但是它们的表现非常糟糕(不是作者的错!)为了使这个得到可接受的东西(我需要亚秒返回)我重构了表格以包含{{1列。此列在每个插入上更新以设置该行的生命周期。如果某行没有替代条目,则结束日期设置为9999-12-31。我上面的例子变成......
end_date
然后我可以从接受的答案中删除第二个连接,并在内连接中添加一个额外的子句。
AC_ID | POS_ID | ASAT | END_DATE | VAL
1 | 1 | 2016-01-01 | 2016-01-03 | 100
1 | 2 | 2016-01-01 | 2016-01-02 | 200
1 | 2 | 2016-01-02 | 9999-12-31 | 250
1 | 1 | 2016-01-03 | 9999-12-31 | 0
2 | 1 | 2016-01-02 | 2016-01-04 | 500
3 | 7 | 2016-01-02 | 2016-01-03 | 1000
3 | 7 | 2016-01-03 | 9999-12-31 | 1000
3 | 12 | 2016-01-03 | 9999-12-31 | 5000
2 | 1 | 2016-01-04 | 9999-12-31 | 750
答案 0 :(得分:2)
这应该可以满足您的需求:
SELECT
P1.ac_id,
P1.asat,
SUM(P2.val) AS total_value
FROM
(SELECT DISTINCT P.ac_id, P.asat FROM dbo.Position P) P1
INNER JOIN dbo.Position P2 ON
P2.ac_id = P1.ac_id AND
P2.asat <= P1.asat
LEFT OUTER JOIN dbo.Position P3 ON
P3.ac_id = P1.ac_id AND
P3.pos_id = P2.pos_id AND
P3.asat > P2.asat AND
P3.asat <= P1.asat
WHERE
P3.ac_id IS NULL
GROUP BY
P1.ac_id,
P1.asat
该查询会获取您的所有ac_id
/ asat
组合,然后抓取可能属于需要合计的行的所有行,最后使用LEFT OUTER JOIN
并检查NULL
消除任何不是特定pos_id
的最新行。
答案 1 :(得分:1)
这不是特别有效,但我认为它应该做你想要的:
SELECT aa.AC_ID, aa.ASAT, SUM(p.VAL)
FROM (SELECT DISTINCT AC_ID, ASAT FROM POSITION
) aa JOIN
POSITION P
ON p.AC_ID = aa.AC_ID and p.ASAT <= aa.ASAT
WHERE P.ASAT = (SELECT MAX(P2.ASAT)
FROM POSITION P2
WHERE P.AC_ID = P2.AC_ID AND
P.POS_ID = P2.POS_ID AND
P2.ASAT <= aa.ASAT
)
GROUP BY aa.AC_ID, aa.ASAT;