Trädvy Permalänk
Medlem
Registrerad
Nov 2005

Hjälp med SQL-query

Jag har en tabell med en order log och vill få ut ordrar som inte blivit aktiverade.
Såhär
id order_id status
1 10 Created
2 10 Activated
3 11 Created
4 12 Created
4 12 Activated

Jag vill alltså endast få ut order_id 11 i detta fallet. Kan jag få ut det med en SQL-fråga(MySQL) ?

Trädvy Permalänk
Medlem
Plats
SweClockers forum
Registrerad
Aug 2012

SELECT * FROM table WHERE status <> "Activated"?

EDIT: Missförstod hur loggen fungerade.

Guide: Roota din HTC - BB-Kod-knappar på Prisjakt

              Min burk - Kvävekyld till 80%
Phenom II X4 965@3900MHz (Sommarklock)
GTX 760@1111MHz

Ibland har jag fel, men då är det någon annans fel.

Trädvy Permalänk
Medlem
Plats
i din garderob
Registrerad
Sep 2007
Skrivet av Meto:

Jag har en tabell med en order log och vill få ut ordrar som inte blivit aktiverade.
Såhär
id order_id status
1 10 Created
2 10 Activated
3 11 Created
4 12 Created
4 12 Activated

Jag vill alltså endast få ut order_id 11 i detta fallet. Kan jag få ut det med en SQL-fråga(MySQL) ?

select * from order_log where order_id not in (select order_id from order_log where status = 'Activated')

edit: lyckades paja queryn med en dum uppdatering. Fixat

Bilanaloger är som Volvo — varenda svenne kör med dem

Trädvy Permalänk
Medlem
Registrerad
Nov 2005
Skrivet av Teknocide:

select * from order_log where order_id not in (select order_id from order_log where status = 'Activated')

edit: lyckades paja queryn med en dum uppdatering. Fixat

Tack det krävs alltså en subquery

Trädvy Permalänk
Medlem
Plats
i din garderob
Registrerad
Sep 2007
Skrivet av Meto:

Tack det krävs alltså en subquery

Det krävs inte en subquery men det är tydligast.

Nedanstående väljer ut alla order_ids som bara förekommer en gång. Förutsatt att det alltid finns en Created-rad innan en Activated-rad läggs till bör den ge samma resultat som den tidigare frågan, fast i en query.

select order_id from order_log group by order_id having count(*) = 1

Bilanaloger är som Volvo — varenda svenne kör med dem

Trädvy Permalänk
Medlem
Registrerad
Aug 2002
Skrivet av Teknocide:

Det krävs inte en subquery men det är tydligast.

Nedanstående väljer ut alla order_ids som bara förekommer en gång. Förutsatt att det alltid finns en Created-rad innan en Activated-rad läggs till bör den ge samma resultat som den tidigare frågan, fast i en query.

select order_id from order_log group by order_id having count(*) = 1

Dock är väl det där ingen lösning man vill göra, den tidigare du postade är ju multum bättre.

Jag satt (skönt att den delen av mitt arbetsliv är över) och lagade sånna här saker dagarna i ända förut.

Det göra aldeles för många antaganden, samtidigt som den miserabelt breakar så fort nån annan får för sig att ändra/uppgradera systemet som loggar.

T ex kanske nån tycker det är en bra ide att märka upp felaktiga saker med en "error" status, helt plötsligt kan då flödet bli "created->error", och så försvinner dessa ordrar.

Eller ingen behöver ens ha ändrat något, det kanske aldrig var nån som hade använt error-statusen tidigare.

För att den där lösningen ska fungera måste man ju garantera att set aldrig är nått annat än just exakt dessa två statusar i korrekt ordning, inga dubletter, ingenting som går till "activated" direkt utan en created osv.

Rätt självklara antaganden, men jag har fasen sett allt
Skickades från m.sweclockers.com

Trädvy Permalänk
Medlem
Registrerad
Okt 2007

select * from tabell where status = "Created"
Får du ut alla som inte är Aktiverade iaf

Ryzen 1700 @3,8Ghz 1,342V | Corsair Vengeance LPX 2x8Gb (CMK16GX4M2B3000C15) | Asus Prime x370 Pro | MSI GTX 770 2GB SLI

Trädvy Permalänk
Medlem
Plats
Malmö
Registrerad
Maj 2004
Skrivet av Tony32:

select * from tabell where status = "Created"
Får du ut alla som inte är Aktiverade iaf

Du har missuppfattat, läs detta igen: "Jag vill alltså endast få ut order_id 11 i detta fallet."
Din query spottar även ut order_id 10 och order_id 12

Lägg märke till att rad 1 & 2 samt rad 4 & 5 är samma order_id, bara två olika 'states'

Trädvy Permalänk
Medlem
Registrerad
Aug 2002
Skrivet av Tony32:

select * from tabell where status = "Created"
Får du ut alla som inte är Aktiverade iaf

Detta är en loggtabell, varje order_id kan alltså ha multipla rader.
Läs om och läs rätt

Skickades från m.sweclockers.com

Trädvy Permalänk
Medlem
Registrerad
Okt 2015

Varför sätter du inte en boolean flagga som heter created?
Då kan du bara köra
SELECT * FROM log WHERE created = false;

När du skapat upp något så sätter du flaggan till true med en update bara. Slippa dubbla. Bara ha en createdAt och en updatedAt kolumn som håller tiden som skapades så kan du rada upp efter vilken tid du nu vill göra.

Trädvy Permalänk
Medlem
Plats
Linköping
Registrerad
Dec 2014

Med lite mängdfunktioner borde det gå under förutsättningarna att
1) Alla ordrar som skapas får en log-rad med Created
2) Alla ordrar (om fler statusar finns) passerar (loggar) Activated.

SELECT order_id FROM order_log WHERE status = 'Created' MINUS SELECT order_id FROM order_log WHERE status = 'Activated'

Trädvy Permalänk
Medlem
Registrerad
Nov 2005

Intressant med så många förslag löst det med subquery tillsvidare.

Skrivet av Teknocide:

Det krävs inte en subquery men det är tydligast.

Nedanstående väljer ut alla order_ids som bara förekommer en gång. Förutsatt att det alltid finns en Created-rad innan en Activated-rad läggs till bör den ge samma resultat som den tidigare frågan, fast i en query.

select order_id from order_log group by order_id having count(*) = 1

ok kan man inte sätta att statusen ska vara created OCH att order_id bara ska förekomma en gång?

Trädvy Permalänk
Medlem
Plats
i din garderob
Registrerad
Sep 2007
Skrivet av Meto:

Intressant med så många förslag löst det med subquery tillsvidare.

ok kan man inte sätta att statusen ska vara created OCH att order_id bara ska förekomma en gång?

"Tillsvidare"? Att använda en subquery är en tydligare och stabilare lösning, inte ett fulhack på något vis. Hur kommer det sig att du inte vill använda en sådan?

Bilanaloger är som Volvo — varenda svenne kör med dem

Trädvy Permalänk
Medlem
Registrerad
Nov 2005
Skrivet av Teknocide:

"Tillsvidare"? Att använda en subquery är en tydligare och stabilare lösning, inte ett fulhack på något vis. Hur kommer det sig att du inte vill använda en sådan?

Tycker det skulle vara bättre med en query (snyggare med mindre kod och borde gå snabbare).
Men ville också höra vad folk föredrar här och hur de löser det. Tycker allmänt att sql ofta känns lite väl bökigt när man vill gruppera flera rader till ett object. Oftast löser jag det med kod men känns som det många gånger borde gå att lösa direkt med SQL.

Trädvy Permalänk
Medlem
Plats
London / Göteborg
Registrerad
Jul 2007

Jag provade lite i MSSQL för att se hur den skulle lösa uppgifterna, helt utan några index (här kan du ju vinna prestanda så det visslar om det!).

Subqueryn är betydligt snabbare; den med grupperingen är nästan dubbelt så långsam.

Jag valde förresten att göra om tabellen lite, att låta statusen återspeglas av en integer:
Så kan man köra:

select order_id from orders group by order_id having max(status) = 1

Lägger man på ett index order_id asc, status asc
så tar helt plötsligt frågan hälften av subquery-frågan... Sen om det är best practice vet jag inte.

När det gäller SQL så gissa inte vad som är snabbast - mät! De flesta SQL-motorer är överjävliga på att optimera.

WS: Bärbar workstation, 2 * Dell U2412M
HTPC: Intel NUC, Canton GLE 496, Yamaha RV-A830, Sanyo PLV-Z700
Server: Intel Xeon E3-1240@3.4 GHz, ESXi, 16GB RAM, 8*2TB RAID-Z2 + SSD-cache
Slösurf: MacBook Air 11,6", Nokia Lumia 925, OnePlus Two
Kamera: Canon EOS 5DII + 1DIII, Canon 100/2.8 Macro, Canon 70-200/2.8L, Canon 24-70/2.8L