L'une des exigences les plus fréquentes, les «désirs» d'une entreprise, est la construction de toutes sortes de notations différentes - «les clients les plus débrouillards», «les postes les plus vendus», «les employés les plus actifs» , ... - un sujet favori de divers tableaux de bord.
Par exemple, dans notre solution d'automatisation de restaurants et de cafés, Presto est très populaire comme ceci:
Mais simplement les «plus» pour toute la période préhistorique sont généralement inintéressants - vous avez vendu un chariot de bottes en feutre il y a 3 ans, et maintenant vous l'avez dans le «plus» des ventes pour toujours. Par conséquent, on veut généralement voir le «sommet» dans un dernier intervalle limité - par exemple, «pour la dernière année» (plus précisément, pour les 12 derniers mois civils).
, : "" . " " - SQL-, "" , , , , 1- - .
, "" , "" TOP-10 - .
( , ):
CREATE TABLE item_stat(
item --
integer
, sum
numeric(32,2)
);
CREATE INDEX ON item_stat(sum DESC);
- . - "" ?..
" "
- , , .
- 12- "" . - . "", - :
CREATE TABLE item_stat(
interval_id -- 0 - , 202001 - 2020, 202002 - , ...
integer
, item
integer
, sum
numeric(32,2)
, UNIQUE(interval_id, item)
);
CREATE INDEX ON item_stat(interval_id, sum DESC);
, "" - , " ". ( Foreign Key, item
):
INSERT INTO item_stat(
interval_id
, item
, sum
)
VALUES
(0, 0, 202012) -- (0, 0), - 2020'12
ON CONFLICT(interval_id, item)
DO UPDATE SET
sum = EXCLUDED.sum; --
(/) , , / - "" :
INSERT INTO item_stat(
interval_id
, item
, sum
)
VALUES
(202001, 1, 100) -- + 2020
, ( 0, 1, 100) -- +
ON CONFLICT(interval_id, item)
DO UPDATE SET
sum = item_stat.sum + EXCLUDED.sum; --
, "" , , :
-- ""
WITH next AS (
SELECT 202101
)
--
, prev AS (
SELECT
sum::integer
FROM
item_stat
WHERE
(interval_id, item) = (0, 0)
)
-- , ,
, diff AS (
SELECT
item
, sum(sum) sum
FROM
item_stat
WHERE
interval_id BETWEEN (TABLE prev) - 100 AND (TABLE next) - 100
GROUP BY
1
)
UPDATE
item_stat dst
SET
sum = dst.sum - diff.sum
FROM
diff
WHERE
(dst.interval_id, dst.item) = (0, diff.item);
UPDATE
item_stat
SET
sum = 202101
WHERE
(interval_id, item) = (0, 0);
, "" - :
SELECT
*
FROM
item_stat
WHERE
interval_id = 0 -- ""
ORDER BY
sum DESC
LIMIT 10;
( , ) - , ( , ) , .