DROP TABLE IF EXISTS buckets;
CREATE TABLE buckets (
bucket_id bigserial primary key,
capacity integer);
-- something to put in the buckets
DROP TABLE IF EXISTS transactions;
CREATE TABLE transactions (
transaction_id bigserial primary key,
quantity integer);
-- create 2 buckets with different capacities
INSERT INTO buckets (capacity)
VALUES (100),(50);
-- create some traffic to put in the buckets
INSERT INTO transactions (quantity)
VALUES (50),(60),(20),(40);
WITH buckets AS (
-- expand buckets (create a row per bucket capacity)
SELECT row_number() OVER () bucket_row_id, *
FROM (
-- slot = a unit of capacity
SELECT *, generate_series(1,b.capacity) slot
FROM buckets b
) useless_alias
), xact AS (
-- expand transactions, creating an id per unit of quantity
SELECT row_number() OVER () unit_row_id, *
FROM (
-- an item per transaction quantity
SELECT *, generate_series(1,t.quantity) unit
FROM transactions t
) useless_alias
), filled AS (
-- join buckets to transactions on slots=units
-- slots with no units = wasted bucket capacity
-- units with no slots = overage
SELECT b.*, x.*
FROM xact x
FULL JOIN buckets b
ON b.bucket_row_id = x.unit_row_id
)
-- finally, do the do
SELECT transaction_id, CASE WHEN bucket_id IS NULL THEN 'overage' ELSE bucket_id::text END bucket_id , count(unit_row_id) quantity_bucketed
FROM filled
GROUP BY 1,2
ORDER BY 1,2
警告:我没有尝试从“超额”中增加一列。填充桶时,超龄不适合哪个桶有点无关紧要。在示例案例中,只有 1 个事务超额。我假设在您的实际用例中,如果有更多交易,您真的希望看到每笔交易的数量没有被分桶。