我有两张桌子。我是T-SQL的新手。
首先选择返回此结果:
ID Quantity
-------------
1 30
2 25
第二个选择返回此结果:
ID Document QuantityS Date
----------------------------------------
1 DocA 12 22-03-2017
1 DocB 10 18-03-2017
1 DocC 10 15-03-2017
1 DocD 8 6-03-2017
2 DocA 20 21-04-2017
2 DocB 12 18-04-2017
2 DocC 10 13-04-2017
我需要在ID上加入这两个表并从第二个表中获取行,而quantityS
的总和大于或等于第一个表中的Quantity
,按Date desc
排序。
我需要得到这样的表:
ID Document QuantityS Date
------------------------------------------
1 DocA 12 22-03-2017
1 DocB 10 18-03-2017
1 DocC 10 15-03-2017
2 DocA 20 21-04-2017
2 DocB 12 18-04-2017
我不需要第二张表的最后一行,因为三行的数量总和是32,大于30。
有什么想法吗?
答案 0 :(得分:0)
您需要windowed aggregate function:
SELECT ItemRecord.id, ItemRecord.document, ItemRecord.quantity, ItemRecord.uploadedOn
FROM ItemLimit
JOIN (SELECT ItemRecord.id, ItemRecord.document, ItemRecord.quantity, ItemRecord.uploadedOn,
COALESCE(SUM(quantity) OVER(PARTITION BY id
ORDER BY uploadedOn DESC
ROWS BETWEEN UNBOUNDED PRECEDING AND 1 PRECEDING), 0) AS runningTotal
FROM ItemRecord) ItemRecord
ON ItemRecord.id = ItemLimit.id
AND ItemRecord.runningTotal <= ItemLimit.quantity
ORDER BY ItemRecord.id, ItemRecord.uploadedOn DESC
那么这是如何工作的?最重要的部分是聚合函数SUM
。您不能只使用常规的,但由于您没有(甚至不想要)GROUP BY
,这意味着您需要使用OVER
子句。第一步:
SELECT id, document, quantity, uploadedOn,
SUM(quantity) OVER() AS runningTotal
FROM ItemRecord
结果:
| id | document | quantity | uploadedOn | runningTotal | |----|----------|----------|------------|--------------| | 1 | DocA | 12 | 2017-03-22 | 82 | | 1 | DocB | 10 | 2017-03-18 | 82 | | 1 | DocC | 10 | 2017-03-15 | 82 | | 1 | DocD | 8 | 2017-03-06 | 82 | | 2 | DocA | 20 | 2017-04-21 | 82 | | 2 | DocB | 12 | 2017-04-18 | 82 | | 2 | DocC | 10 | 2017-04-13 | 82 |
......很明显,这笔款项的金额是多少!这个原因很明显:我们还没有说过&#34;命令&#34;的行是!所以让我们在下一步中包含窗口:
SELECT id, document, quantity, uploadedOn,
SUM(quantity) OVER(ORDER BY uploadedOn DESC) AS runningTotal
FROM ItemRecord
结果:
| id | document | quantity | uploadedOn | runningTotal | |----|----------|----------|------------|--------------| | 1 | DocA | 12 | 2017-03-22 | 54 | | 1 | DocB | 10 | 2017-03-18 | 64 | | 1 | DocC | 10 | 2017-03-15 | 74 | | 1 | DocD | 8 | 2017-03-06 | 82 | | 2 | DocA | 20 | 2017-04-21 | 20 | | 2 | DocB | 12 | 2017-04-18 | 32 | | 2 | DocC | 10 | 2017-04-13 | 42 |
...除了因为某些原因,它没有为id = 1
重启!我们必须将它告诉 partition ,或将结果分开:
SELECT id, document, quantity, uploadedOn,
SUM(quantity) OVER(PARTITION BY id
ORDER BY uploadedOn DESC) AS runningTotal
FROM ItemRecord
结果:
| id | document | quantity | uploadedOn | runningTotal | |----|----------|----------|------------|--------------| | 1 | DocA | 12 | 2017-03-22 | 12 | | 1 | DocB | 10 | 2017-03-18 | 22 | | 1 | DocC | 10 | 2017-03-15 | 32 | | 1 | DocD | 8 | 2017-03-06 | 40 | | 2 | DocA | 20 | 2017-04-21 | 20 | | 2 | DocB | 12 | 2017-04-18 | 32 | | 2 | DocC | 10 | 2017-04-13 | 42 |
......那更好,但我们遇到了问题 - 我们想要第3行,但它太高了!问题在于我们不希望总和包含此行,而只包含前面的行。幸运的是,我们可以指定窗口的边界:
SELECT id, document, quantity, uploadedOn,
SUM(quantity) OVER(PARTITION BY id
ORDER BY uploadedOn DESC
ROWS BETWEEN UNBOUNDED PRECEDING AND 1 PRECEDING) AS runningTotal
FROM ItemRecord
| id | document | quantity | uploadedOn | runningTotal | |----|----------|----------|------------|--------------| | 1 | DocA | 12 | 2017-03-22 | (null) | | 1 | DocB | 10 | 2017-03-18 | 12 | | 1 | DocC | 10 | 2017-03-15 | 22 | | 1 | DocD | 8 | 2017-03-06 | 32 | | 2 | DocA | 20 | 2017-04-21 | (null) | | 2 | DocB | 12 | 2017-04-18 | 20 | | 2 | DocC | 10 | 2017-04-13 | 32 |
...好吧,现在第三行是在界限内,第四行是(仍然)超出范围,但是我们在第一行行遇到了问题:&& #39; s null!这并不令人惊讶:对于第一行,没有前一行,因此没有数量。但它很烦人:null不能与任何东西(甚至是它自己)进行比较,所以我们不能在简单的比较中使用它。幸运的是,有一种方法可以将空值更改为另一个值:
SELECT ItemRecord.id, ItemRecord.document, ItemRecord.quantity, ItemRecord.uploadedOn,
COALESCE(SUM(quantity) OVER(PARTITION BY id
ORDER BY uploadedOn DESC
ROWS BETWEEN UNBOUNDED PRECEDING
AND 1 PRECEDING), 0) AS runningTotal
FROM ItemRecord
哪个收益率:
| id | document | quantity | uploadedOn | runningTotal | |----|----------|----------|------------|--------------| | 1 | DocA | 12 | 2017-03-22 | 0 | | 1 | DocB | 10 | 2017-03-18 | 12 | | 1 | DocC | 10 | 2017-03-15 | 22 | | 1 | DocD | 8 | 2017-03-06 | 32 | | 2 | DocA | 20 | 2017-04-21 | 0 | | 2 | DocB | 12 | 2017-04-18 | 20 | | 2 | DocC | 10 | 2017-04-13 | 32 |
...此时,我们需要的形式,准备加入另一个限制的表。
<小时/> 另外,还有另一种从正在运行的总计中删除当前行的方法,也不需要
COALESCE
。选择当前形式的查询是因为它意味着窗口完全指定了所需的行。这个版本将留给读者练习,或者性能好奇。