SQL
Fönsterfunktioner
Sök…
Lägga till de totala raderna som valts till varje rad
SELECT your_columns, COUNT(*) OVER() as Ttl_Rows FROM your_data_set
id | namn | Ttl_Rows |
---|---|---|
1 | exempel | 5 |
2 | foo | 5 |
3 | bar | 5 |
4 | baz | 5 |
5 | quux | 5 |
I stället för att använda två frågor för att få en räkning sedan linjen, kan du använda ett aggregerat som fönsterfunktion och använda hela resultatuppsättningen som fönster.
Detta kan användas som bas för vidare beräkning utan komplexiteten hos extra självförbindelser.
Ställa in en flagga om andra rader har en gemensam egenskap
Låt oss säga att jag har dessa data:
Tabellobjekt
id | namn | märka |
---|---|---|
1 | exempel | unique_tag |
2 | foo | enkel |
42 | bar | enkel |
3 | baz | Hej |
51 | quux | värld |
Jag skulle vilja få alla dessa rader och veta om en tagg används av andra linjer
SELECT id, name, tag, COUNT(*) OVER (PARTITION BY tag) > 1 AS flag FROM items
Resultatet blir:
id | namn | märka | flagga |
---|---|---|---|
1 | exempel | unique_tag | falsk |
2 | foo | enkel | Sann |
42 | bar | enkel | Sann |
3 | baz | Hej | falsk |
51 | quux | värld | falsk |
Om din databas inte har OVER och PARTITION kan du använda den här för att producera samma resultat:
SELECT id, name, tag, (SELECT COUNT(tag) FROM items B WHERE tag = A.tag) > 1 AS flag FROM items A
Få ett löpande totalt
Med tanke på dessa uppgifter:
datum | belopp |
---|---|
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
kommer att ge dig
datum | belopp | löpning |
---|---|---|
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 |
Få de senaste raderna över flera grupper
Med tanke på dessa uppgifter
Användar ID | COMPLETION_DATE |
---|---|
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
Med n = 1 får du den senaste raden per user_id
:
Användar ID | COMPLETION_DATE | ROW_NUM |
---|---|---|
1 | 2016/07/21 | 1 |
2 | 2016/07/22 | 1 |
Hitta "out-of-sequence" -poster med funktionen LAG ()
Med tanke på dessa exempeldata:
ID | STATUS | STATUS_TIME | STATUS_BY |
---|---|---|---|
1 | ETT | 2016-09-28-19.47.52.501398 | USER_1s |
3 | ETT | 2016-09-28-19.47.52.501511 | USER_2 |
1 | TRE | 2016-09-28-19.47.52.501517 | USER_3 |
3 | TVÅ | 2016-09-28-19.47.52.501521 | USER_2 |
3 | TRE | 2016-09-28-19.47.52.501524 | USER_4 |
Objekt identifierade med ID
värden måste flytta från STATUS
'EN' till 'Två' till 'TRE' i följd, utan att hoppa över statuser. Problemet är att hitta användare ( STATUS_BY
) STATUS_BY
som bryter mot regeln och flyttar från 'ONE' omedelbart till 'THREE'.
LAG()
hjälper till att lösa problemet genom att för varje rad returnera värdet i föregående rad:
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'
Om din databas inte har LAG () kan du använda den här för att producera samma resultat:
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'