Permalänk
Medlem

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) ?

Permalänk
Medlem

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

EDIT: Missförstod hur loggen fungerade.

Visa signatur

Spela Swemantle! Du vet att du vill.

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

Permalänk
Medlem
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

Visa signatur

Kom-pa-TI-bilitet

Permalänk
Medlem
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

Permalänk
Medlem
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

Visa signatur

Kom-pa-TI-bilitet

Permalänk
Medlem
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

Permalänk
Medlem

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

Visa signatur

Ryzen 1700 @3,8Ghz 1,342V | Corsair Vengeance LPX 2x8Gb (CMK16GX4M2B3000C15) | Asus Prime x370 Pro | KFA2 GTX 1080 Ti

Permalänk
Medlem
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'

Permalänk
Medlem
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

Permalänk

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.

Permalänk
Medlem

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'

Stilfel
Permalänk
Medlem

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?

Permalänk
Medlem
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?

Visa signatur

Kom-pa-TI-bilitet

Permalänk
Medlem
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.

Permalänk
Medlem

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.

Visa signatur

Jag är en optimist; det är aldrig så dåligt så att det inte kan bli sämre.