WN

WN (https://www.wn.se/forum/index.php)
-   Serversidans teknologier (https://www.wn.se/forum/forumdisplay.php?f=4)
-   -   Problem med SQL-fråga (https://www.wn.se/forum/showthread.php?t=1044736)

Robert 2010-11-09 17:53

Problem med SQL-fråga
 
Hej på er,

Sitter fast i SQL-träsket med en fråga jag inte får till...
Nedan har jag två (fejkade) tabeller, en för användare och en för adresser. En användare kan ha flera adresser där ett datum bestämmer vilken adress som är den senaste (aktuella).

Hur gör jag för att selektera ut samtliga users och joina in endast den senaste adressen för varje user? Det som ställer till det för mig är att jag vill kunna selekta ut alla kolumner från adress-tabellen (svårt att göra en group by med andra ord)
Kod:

Users:
UserId  Name
================
1        Nisse
2        Kalle
3        Gustav

Adress:
========================
AdressId UserId  Street  Date
1          1        Road1  2008-11-01
2          2        Road2  2008-11-01
3          3        Road3  2008-11-01
4          3        Road4  2009-11-01
5          3        Road5  2010-05-01


Magnus_A 2010-11-09 18:09

Pröva med att ha en sammansatt index med autoincrement som bygger på båda kolumnerna AdressId och UserId i adress-tabellen

Då kommer tabellen att se ut så här:
Adress:
========================
Kod:

AdressId UserId  Kombo_Autoincrement Street  Date
1          1              1                            Road1  2008-11-01
2          2              1                              Road2  2008-11-01
3          3              1                              Road3  2008-11-01
4          3              2                            Road4  2009-11-01
5          3              3                            Road5  2010-05-01


Robert 2010-11-09 19:45

Hmmm, jag har tyvär bara möjlighet att skriva frågor, inte ändra i databasstrukturen. Det var väl det ditt förslag gick ut på?

dAEk 2010-11-09 19:55

Kod:

select
        u.*,
        a.*
from
        Users u
        join [Address] a on a.UserId = u.UserId and a.AddressId = (select top 1 AddressId from [Address] where UserId = u.UserId order by [Date] desc)

Koden är otestad så det kanske inte funkar eller går ohyggligt långsamt men jag tycker att det ser ok ut. :)

Robert 2010-11-09 20:35

Citat:

Ursprungligen postat av dAEk (Inlägg 20377277)
Koden är otestad så det kanske inte funkar eller går ohyggligt långsamt men jag tycker att det ser ok ut. :)

Tackar, det verkar fungera rakt av faktiskt, jag har lite dåligt med testdata för att kontrollera det. Men jag ser iaf din idé och det verkar vara så man ska gå till väga! :)

martine 2010-11-11 12:30

Citat:

Ursprungligen postat av dAEk (Inlägg 20377277)
Koden är otestad så det kanske inte funkar eller går ohyggligt långsamt men jag tycker att det ser ok ut. :)

Man kan ju tillägga att subqueries kan bli enormt långsamma.

Varför man inte skulle använda en join med group by här har jag svårt att förstå.

dAEk 2010-11-11 21:23

Uppdaterat 2010-11-12:

Med 1 miljon rader i båda tabellerna tog frågan ca 6 sekunder (~19 allt som allt, inkl. att returnera alla rader) att köra på min 5 år gamla burk.

Körde sedan frågan genom query tuning analysern och det visade sig att jag inte hade bra index. Med ett nytt index som innehåller både UserId och Date körs frågan omedelbums. Det som tar tid är att returnera raderna (~14 sek).

Hur som helst: Sql är inte mitt starkaste område så andra lösningar är fortfarande intressanta.

Hur skulle du skriva frågan?

Magnus_A 2010-11-11 22:03

När man använder group by är det svårt att styra vilken rad i gruppen som väljs ut. Enligt mina erfarenheter är det den första raden, och man skulle kunna styra det genom att sortera tabellen i förväg. Men det är odokumenterat och jag skulle inte lite på det. Subquery är nog vägen att gå här, om man inte kan göra tabellen på ett bättre sätt.

dAEk 2010-11-26 20:39

Citat:

Ursprungligen postat av martine (Inlägg 20377520)
Man kan ju tillägga att subqueries kan bli enormt långsamma.

Varför man inte skulle använda en join med group by här har jag svårt att förstå.

Två veckor senare väntar vi fortfarande på en bättre lösning.

tartareandesire 2010-11-26 20:58

Citat:

Ursprungligen postat av Magnus_A (Inlägg 20377651)
När man använder group by är det svårt att styra vilken rad i gruppen som väljs ut. Enligt mina erfarenheter är det den första raden, och man skulle kunna styra det genom att sortera tabellen i förväg. Men det är odokumenterat och jag skulle inte lite på det. Subquery är nog vägen att gå här, om man inte kan göra tabellen på ett bättre sätt.

Såvida man inte byter databas så fungerar det alldeles utmärkt men som du säger så är det ingenting som finns dokumenterat. Jag ser heller ingen annan utväg än att göra en subquery men att då också se till att ha indexerat ordentligt. Det optimala hade varit att flagga aktuell adress eller helt enkelt bara arkivera gamla adresser för att få en betydligt mindre tabell att arbeta med (om den nu är alltför stor) men nu finns uppenbarligen inte det alternativet tillgängligt av någon anledning.

Om ni verkligen inte har möjlighet att ändra databasen på något vis så skulle en extrem alternativ lösning vara att spara varje användare med nuvarande adress i en fil.

Clarence 2010-11-26 23:10

Det finns egentligen två alternativ för att göra det effektivt:
- Anpassa tabellstrukturerna efter datan och frågorna som ska ställas mot den. Skulle enkelt kunna innebära att endast ha en extra relationstabell mellan dom, men det saknas något effektivt unikt att koppla mot i adress-strukturen ovan. Alternativet vore att ha en flagga i adress-tabellen för aktuell adress.
- Cacha den relevanta datan i en separat tabell/plats.

Och sen det sista alternativet. Använda en query som ovan med en subquery vilket (i de allra flesta fall) resulterar i en väldig overhead.


Alla tider är GMT +2. Klockan är nu 22:50.

Programvara från: vBulletin® Version 3.8.2
Copyright ©2000 - 2025, Jelsoft Enterprises Ltd.
Svensk översättning av: Anders Pettersson