[SQL] select van laatse uniek waardes

Pagina: 1
Acties:

Onderwerpen


Acties:
  • 0 Henk 'm!

Verwijderd

Topicstarter
De deuren bij ons in de club gaan open met een keycard. Iedere persoon heeft zijn eigen keycard. Bij het lezen van de keycard wordt telkens een record in een tabel toegevoegd.

De tabel "doorLog":

IDcardIDdoorIDtime
11204/06/2010 15:30
21103/06/2010 11:30
32304/06/2010 17:03
41205/06/2010 12:19
52106/06/2010 09:42



Om op te vragen wie welke deur het laatst geopend heeft gebruiken we nu een heel simpele query:

select cardID, doorID, time from doorLog where doorID = '1' order by ID desc limit 1;


We willen nu echter een overzicht pagina maken met per persoon wanneer hij welke deur het laatst geopend heeft maar ik raak er totaal niet aan uit hoe ik zo'n query moet maken.

Kan iemand me hier in de goed richting helpen?

Acties:
  • 0 Henk 'm!

  • Jaap-Jan
  • Registratie: Februari 2001
  • Laatst online: 11-09 13:16
Dat kun je doen met een GROUP BY. :)

[ Voor 111% gewijzigd door Jaap-Jan op 08-10-2010 10:40 ]

| Last.fm | "Mr Bent liked counting. You could trust numbers, except perhaps for pi, but he was working on that in his spare time and it was bound to give in sooner or later." -Terry Pratchett


Acties:
  • 0 Henk 'm!

  • Davio
  • Registratie: November 2007
  • Laatst online: 06-01 16:46
Misschien moet je even oppassen met het sorteren op ID.

De ID-volgorde is namelijk de volgorde waarop de rijen in de database worden aangemaakt en niet per se de volgorde waarop de personen binnen zijn gekomen. Als er bijvoorbeeld een heleboel personen vlak na elkaar binnenkomen en de rijen worden allemaal tegelijk aangemaakt, kan hier wel eens een verschil ontstaan.

Veiliger lijkt me dan gewoon om op time te sorteren.

Acties:
  • 0 Henk 'm!

  • mjax
  • Registratie: September 2000
  • Laatst online: 08:12
Dus iets van:

SELECT cardID, doorID, MAX(time) FROM doorLog GROUP BY cardID, doorID

Deze zou je dan (niet getest) voor iedereen, voor elke deur aangeven wanneer die voor het laatst geopend is.

[ Voor 39% gewijzigd door mjax op 08-10-2010 10:44 ]


Acties:
  • 0 Henk 'm!

  • Jaap-Jan
  • Registratie: Februari 2001
  • Laatst online: 11-09 13:16
quote: Lao Tzu
"Give a man a fish and you feed him for a day. Teach a man to fish and you feed him for a lifetime."
of
quote: Terry Pratchett
"Build a man a fire, and he'll be warm for a day. Set a man on fire, and he'll be warm for the rest of his life."
Maargoed, de strekking is duidelijk, lijkt me. :P

| Last.fm | "Mr Bent liked counting. You could trust numbers, except perhaps for pi, but he was working on that in his spare time and it was bound to give in sooner or later." -Terry Pratchett


Acties:
  • 0 Henk 'm!

  • ReenL
  • Registratie: Augustus 2010
  • Laatst online: 14-09-2022
mjax schreef op vrijdag 08 oktober 2010 @ 10:44:
Dus iets van:

SELECT cardID, doorID, MAX(time) FROM doorLog GROUP BY cardID, doorID

Deze zou je dan (niet getest) voor iedereen, voor elke deur aangeven wanneer die voor het laatst geopend is.
Deze query geeft voor elke kaart terug wanneer hij als laatst een bepaalde deur open gemaakt heeft. Niet welke deur een bepaalde kaart als laatst heeft opengemaakt.

Denk dat je zoiets zoekt (niet getest):
SQL:
1
2
3
4
SELECT d.cardID, MAX(d.time) AS t, j.doorID 
FROM doorLog d 
LEFT JOIN doorLog j ON (d.cardID = j.cardID AND d.time = j.time)
GROUP BY d.cardID

Overigens zou het in mysql misschien makkelijker kunnen omdat group by buggy werkt.

En ja ik geef nu de vis, maar dit is niet iets wat je zomaar even uitzoekt. De hengel is: Je kunt ook een tabel aan zichzelf laten joinen.

Acties:
  • 0 Henk 'm!

  • lier
  • Registratie: Januari 2004
  • Laatst online: 12:19

lier

MikroTik nerd

ReenL schreef op vrijdag 08 oktober 2010 @ 14:43:
Deze query geeft voor elke kaart terug wanneer hij als laatst een bepaalde deur open gemaakt heeft. Niet welke deur een bepaalde kaart als laatst heeft opengemaakt.

Denk dat je zoiets zoekt (niet getest):
SQL:
1
2
3
4
SELECT d.cardID, MAX(d.time) AS t, j.doorID 
FROM doorLog d 
LEFT JOIN doorLog j ON (d.cardID = j.cardID AND d.time = j.time)
GROUP BY d.cardID

Overigens zou het in mysql misschien makkelijker kunnen omdat group by buggy werkt.

En ja ik geef nu de vis, maar dit is niet iets wat je zomaar even uitzoekt. De hengel is: Je kunt ook een tabel aan zichzelf laten joinen.
Ik denk dat je een vergissing maakt:

ten eerste in de GROUP BY ontbreekt j.doorID (waardoor de expressie al niet goed is, los van de functie)
ten tweede is "de mjax oplossing" juist: de combinatie doorID en cardID met de bijbehorende MAX(time) levert exact hetgeen de TS zoekt:
per persoon wanneer hij welke deur het laatst geopend

Eerst het probleem, dan de oplossing


Acties:
  • 0 Henk 'm!

Verwijderd

Topicstarter
De gebruikte database is trouwens PostgreSQL.

Dank jullie voor me in de juiste richting te begeleiden. Ik ben er uiteindelijk in geslaagd een werkende query te maken maar het heeft toch heel wat voeten in de aarde gehad.

De originele tabel heeft ook nog een extra veld waar ik eerst geen belang aan gehecht had maar die we uiteindelijk wel nodig hebben. Iedere keycard heeft ook een level, dit moest ook weergegeven worden.


De tabel is dan zo:

IDcardIDdoorIDleveltime
112a04/06/2010 15:30
211b03/06/2010 11:30
323a04/06/2010 17:03
412c05/06/2010 12:19
521a06/06/2010 09:42


De uiteindelijke query is:

code:
1
2
3
4
5
6
7
8
9
select t."cardID", t."doorID", t.level, t.time
from "doorLog" t,
(select "cardID", "doorID", max(time) as dt
from "doorLog"
group by "doorID", "cardID") f
where t."doorID" = f."doorID"
and t."cardID" = f."cardID"
and t.time = f.dt
order by t."cardID", t.doorID;
Pagina: 1