Frühesten Eintrag am Tag erkennen

skruffes

Benutzer
Beiträge
17
Hallo,

kurze Einführung zu meinem Projekt.

Es geht um mehrere Skigebiete bei denen ich für Skifahrer die Ticketpreise berechnen möchte. Hierzu werden jede Nacht die Tickets aus der DB gelesen und die Preise berechnet.

Ich möchte ein weiteres Feature einbauen und zwar Spartickets. Hier werden besondere Rabatte gewährleistet, wenn man an einem Tag in mehreren Skigebieten (SkiAreaId) unterwegs ist. Wichtig ist, dass hier immer der Preis des ersten Skigebietes genommen wird und für die anderen besuchten Skigebiete am Tag nur eine Gästekarte ausgegeben wird.

Meine Frage:

Wie erkenne ich ob es an einem Tag mehrere Einträge eines Users gegeben hat und wie finde ich heraus welches der früheste ist? Ein User hat immer eine ID, ein Skigebiet hat eine ID und es wird immer die Fahrtzeit von - bis gespeichert.

Theoretisch müsste ich also ein Query erstellen dass mir alle User gibt die an einem Tag mehr als 1mal vorkommen. Dies zweimal, da ich zuerst jeweils den ersten Eintrag haben möchte und dann erst die anderen.

Kann mir hier jemand einen Tipp geben wie ich das in SQL schreiben kann? Bin hier leider erst an den Anfängen :)

Vielen Dank!
 
Werbung:
Ich würde mit EXISTS arbeiten, es gibt aber viele Wege. Hermit findest du alle User die am Tag X (Variable @datum) mehr als eine Fahrt gemacht haben:
Code:
SELECT    f1.id_user
FROM    fahrten f1
WHERE    f1.datum = @datum
AND EXISTS (    SELECT    1
                FROM    fahrten f2
                WHERE    f2.id_user = f1.id_user
                AND        f2.datum = f1.datum
                AND        f2.SkiAreaID <> f1.SkiAreaID )
Mit ORDER BY und LIMIT bekommst du die erste Fahrt:
Code:
SELECT   f1.id_user,
     f1.id_fahrt
FROM   fahrten f1
WHERE   f1.datum = @datum
AND EXISTS (   SELECT   1
         FROM   fahrten f2
         WHERE   f2.id_user = f1.id_user
         AND     f2.datum = f1.datum
         AND     f2.SkiAreaID <> f1.SkiAreaID )
ORDER BY f1.von
LIMIT 1
Und mit OFFSET alle weiteren:
Code:
SELECT    f1.id_user,
        f1.id_fahrt
FROM    fahrten f1
WHERE    f1.datum = @datum
AND EXISTS (    SELECT    1
                FROM    fahrten f2
                WHERE    f2.id_user = f1.id_user
                AND        f2.datum = f1.datum
                AND        f2.SkiAreaID <> f1.SkiAreaID )
ORDER BY f1.von
OFFSET 1
Ich weiß nur nicht ob OFFSET ohne LIMIT geht, das musst du mal testen.
 
Hallo,

bin jetzt endlich zum Testen gekommen und habe gleich ein Problem.

Bei dir steht nur eine Tabelle "fahrten f1". Im zweiten Select kommt dann f2 hinzu.
Meine Abfrage beinhaltet leider Joins von 6 Tabellen. Wie stelle ich hier den Query zusammen? Bin hier etwas verwirrt :/
 
Ohne deine Tabellenstruktur und dein Query zu kennen kann ich das nicht beantworten. Die Joins werden vermutlich einen Sinn erfüllen, also gehe ich mal davon aus das du sie im eigentlichen Select genauso machen musst wie bisher. Im Subselect nach EXISTS brauchst du nur die Spalten, die auch im WHERE geprüft werden.
 
Ok hier ist mein eigentliches Query (Tabellennamen wurden etwas geändert):

Als Ergebnis bekomme ich alle User die an diesen Tag ein Ticket gelöst haben.

Code:
SELECT
    cs.id AS resortId,
    ul.des AS description,
    ul.valA AS billed_amount,
    ul.aA AS actual_amount,
    u.id AS user_id,
    cr. birthday AS birthday,
    ul.dateFrom AS firstGate,
    ul.dateTo AS lastGate

FROM
    tb_user p JOIN tb_userList ul ON p.nkey = ul.nkey
    AND p.data_ut = ul.dateFrom JOIN tb_card_reg cr ON ul.nkey = cr.num_card JOIN tb_ul u ON cr.id_ut = u.id_ut
    LEFT JOIN tb_card_batches cb ON pv.nkey = cb.cardId JOIN tb_cs cs ON p.ns = cs.id
  
WHERE

(cs.id = 2 OR cs.id = 3 OR cs.id=5)
AND
  pv.dateTo between '2014-12-23' and '2014-12-23 23:59:59')

Jetzt würde ich gern vom 23.12.2014 immer nur die User haben, die 1. mindestens 2 mal vorkommen und 2. von denen immer nur den ersten Eintrag. (= den frühesten Wert von firstGate)

Ich hoffe mein Ziel ist verständlich :/
 
Ohne deinen Aufbau wirklich zu verstehen würde ich sagen in etwa so:
Code:
SELECT   cs.id AS resortId,
     ul.des AS description,
     ul.valA AS billed_amount,
     ul.aA AS actual_amount,
     u.id AS user_id,
     cr. birthday AS birthday,
     ul.dateFrom AS firstGate,
     ul.dateTo AS lastGate
FROM   tb_user p
INNER JOIN tb_userList ul
ON     p.nkey = ul.nkey
AND     p.data_ut = ul.dateFrom
INNER JOIN tb_card_reg cr
ON     ul.nkey = cr.num_card
INNER JOIN tb_ul u
ON     cr.id_ut = u.id_ut
LEFT JOIN tb_card_batches cb
ON     ul.nkey = cb.cardId
INNER JOIN tb_cs cs
ON     p.ns = cs.id
WHERE   date(ul.dateTo) = '2014-12-23'
AND cs.id IN ( 2,3,5 )
AND EXISTS (   SELECT   1
         FROM   tb_user
         INNER JOIN tb_userList
         ON     tb_user.nkey = tb_userList.nkey
         AND     tb_user.data_ut = tb_userList.dateFrom
         INNER JOIN tb_card_reg
         ON     tb_userList.nkey = tb_card_reg.num_card
         INNER JOIN tb_ul
         ON     tb_card_reg.id_ut = tb_ul.id_ut
         INNER JOIN tb_cs
         ON     tb_user.ns = tb_cs.id
         WHERE cs.id IN ( 2,3,5 )
         AND     tb_ul.id = u.id
         AND     date(tb_userList.dateTo) = date(ul.dateTo)
         AND     tb_cs.id <> cs.id )
LIMIT 1
 
Danke für den Code!

Sehe ich das richtig dass du im Exists Teil die gleichen Tabellen Joinst ohne die Benennungen?

Bekomme hier leider den Fehler: select command denied to user ... for table tb_ul

Verstehst du das?
Danke noch einmal!
 
Im EXISTS-Teil joine ich alle Tabellen mit ihren originären Namen, ich könnte aber auch einen Alias verwenden. Wichtig ist, das sich die Aliase unterscheiden, also z.B. im normalen Select Alias1 und im Subselect Alias2. Dann vergleiche ich im WHERE-Teil vom Subselect die Werte mit den Werten außerhalb des Subselects, daher auch die Unterscheidung.

Das geht bei MSSQL problemlos, bei MySQL habe ich aber schonmal erlebt das er aus dem Subselect nicht auf den Hauptselect kommt, das scheint auch hier der Fall zu sein. Es geht sicherlich auch anders, ich bin mir aber nicht ganz schlüssig wie es am sinnvollsten ist.

Zunächst solltest du deinen ursrpünglichen 6-fach-Join eventuell mal als View anlegen. Dann lassen sich Abfragen darauf ganz einfach aufbauen und sind nicht mit soviel Code verbunden.
 
Werbung:
Zurück
Oben