【发布时间】:2016-05-09 11:08:03
【问题描述】:
我见过很多类似的问题,但没有什么能完全解决我的具体问题。
我有一个表格,为每个帐户存储多个头寸。更改存储为增量。因此,以第 1 天为例...
AC_ID | POS_ID | ASAT | VAL
1 | 1 | 2016-01-01 | 100
1 | 2 | 2016-01-01 | 200
2016 年 1 月 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])
我现在想做的是编写一个查询,它将为每个ASAT 提供每个AC_ID 的总值。如果不是增量存储机制,我可以使用
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
我改变了它的工作方式
虽然下面的答案有效,但它们的性能却非常糟糕(这不是作者的错!)为了得到可接受的结果(我需要亚秒级返回)我重构了表格以包含 end_date柱子。此列在每次插入时都会更新,以设置该行的生命周期。如果一行没有替代条目,则结束日期设置为 9999-12-31。我上面的例子变成了……
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
然后我可以从接受的答案中删除第二个连接,并在内部连接中添加一个额外的子句。
SELECT
p1.AC_ID,
p1.ASAT,
SUM(p2.VAL) as totalValue
FROM
(SELECT DISTINCT AC_ID, ASAT FROM position) p1
INNER JOIN position p2 ON
p2.AC_ID = p1.AC_ID AND
p2.ASAT <= p1.ASAT AND
p2.END_DATE > p1.END_DATE
GROUP BY
p1.AC_ID,
p1.ASAT;
【问题讨论】:
-
如果给定日期没有值怎么办?你还想要那个日期吗?
-
最好不要,即我只对表中列出的日期感兴趣,但如果为了实现这一点,我必须填写其间的每个日期,那么这应该没什么大不了的.日期间隔可能只有 1 或 2 天。
-
澄清一下,任何日期都会有一个值,因为它将是它之前的最新不同头寸的总和。例外情况是,如果日期在任何位置之前存在,在这种情况下结果将为 null/0