SQL
Fonctions de fenêtre
Recherche…
Ajout du nombre total de lignes sélectionnées à chaque ligne
SELECT your_columns, COUNT(*) OVER() as Ttl_Rows FROM your_data_set
id | prénom | Ttl_Rows |
---|---|---|
1 | Exemple | 5 |
2 | foo | 5 |
3 | bar | 5 |
4 | baz | 5 |
5 | quux | 5 |
Au lieu d'utiliser deux requêtes pour obtenir un compte, vous pouvez utiliser un agrégat comme fonction de fenêtre et utiliser l'ensemble de résultats complet comme fenêtre.
Cela peut être utilisé comme base pour un calcul ultérieur sans la complexité des auto-jointures supplémentaires.
Configuration d'un indicateur si d'autres lignes ont une propriété commune
Disons que j'ai ces données:
Articles de table
id | prénom | marque |
---|---|---|
1 | Exemple | unique_tag |
2 | foo | simple |
42 | bar | simple |
3 | baz | Bonjour |
51 | quux | monde |
Je voudrais obtenir toutes ces lignes et savoir si un tag est utilisé par d'autres lignes
SELECT id, name, tag, COUNT(*) OVER (PARTITION BY tag) > 1 AS flag FROM items
Le résultat sera:
id | prénom | marque | drapeau |
---|---|---|---|
1 | Exemple | unique_tag | faux |
2 | foo | simple | vrai |
42 | bar | simple | vrai |
3 | baz | Bonjour | faux |
51 | quux | monde | faux |
Si votre base de données n'a pas OVER et PARTITION, vous pouvez l'utiliser pour produire le même résultat:
SELECT id, name, tag, (SELECT COUNT(tag) FROM items B WHERE tag = A.tag) > 1 AS flag FROM items A
Obtenir un total cumulé
Compte tenu de ces données:
rendez-vous amoureux | montant |
---|---|
2016-03-12 | 200 |
2016-03-11 | -50 |
2016-03-14 | 100 |
2016-03-15 | 100 |
2016-03-10 | -250 |
SELECT date, amount, SUM(amount) OVER (ORDER BY date ASC) AS running
FROM operations
ORDER BY date ASC
te donnera
rendez-vous amoureux | montant | fonctionnement |
---|---|---|
2016-03-10 | -250 | -250 |
2016-03-11 | -50 | -300 |
2016-03-12 | 200 | -100 |
2016-03-14 | 100 | 0 |
2016-03-15 | 100 | -100 |
Obtenir les N lignes les plus récentes sur plusieurs regroupements
Compte tenu de ces données
Identifiant d'utilisateur | Date d'achèvement |
---|---|
1 | 2016-07-20 |
1 | 2016-07-21 |
2 | 2016-07-20 |
2 | 2016-07-21 |
2 | 2016-07-22 |
;with CTE as
(SELECT *,
ROW_NUMBER() OVER (PARTITION BY User_ID
ORDER BY Completion_Date DESC) Row_Num
FROM Data)
SELECT * FORM CTE WHERE Row_Num <= n
En utilisant n = 1, vous obtenez la dernière ligne par user_id
:
Identifiant d'utilisateur | Date d'achèvement | Row_Num |
---|---|---|
1 | 2016-07-21 | 1 |
2 | 2016-07-22 | 1 |
Recherche d'enregistrements "hors séquence" à l'aide de la fonction LAG ()
Compte tenu de ces exemples de données:
ID | STATUT | STATUS_TIME | STATUS_BY |
---|---|---|---|
1 | UN | 2016-09-28-19.47.52.501398 | USER_1 |
3 | UN | 2016-09-28-19.47.52.501511 | USER_2 |
1 | TROIS | 2016-09-28-19.47.52.501517 | USER_3 |
3 | DEUX | 2016-09-28-19.47.52.501521 | USER_2 |
3 | TROIS | 2016-09-28-19.47.52.501524 | USER_4 |
Les éléments identifiés par ID
valeurs ID
doivent passer de STATUS
'ONE' à 'TWO' à 'THREE' dans l'ordre, sans ignorer les statuts. Le problème est de trouver des utilisateurs ( STATUS_BY
) qui violent la règle et passent de «UN» immédiatement à «TROIS».
La fonction analytique LAG()
aide à résoudre le problème en renvoyant pour chaque ligne la valeur de la ligne précédente:
SELECT * FROM (
SELECT
t.*,
LAG(status) OVER (PARTITION BY id ORDER BY status_time) AS prev_status
FROM test t
) t1 WHERE status = 'THREE' AND prev_status != 'TWO'
Si votre base de données n’a pas de LAG (), vous pouvez l’utiliser pour produire le même résultat:
SELECT A.id, A.status, B.status as prev_status, A.status_time, B.status_time as prev_status_time
FROM Data A, Data B
WHERE A.id = B.id
AND B.status_time = (SELECT MAX(status_time) FROM Data where status_time < A.status_time and id = A.id)
AND A.status = 'THREE' AND NOT B.status = 'TWO'