Problème de SQL.

Résolu
Noubli -  
 Noubli -
Bonjour,
Je me casse la tête à essayer de trouver une requête en SQL un peu compliquée.
En fait, j'ai une table "Reservation", avec une heuredébutreservation et une heurefinreservation.
Ce que je voudrais faire, c'est à partir d'un horaire minimum, (exemple 5:00 AM) et une heure maximum (11:00 PM), avoir une liste des "créneaux" qui restent.

Par exemple, si j'ai une reservation entre 8:00 AM et 11:00 AM, je voudrais que la requete me retourne :
5:00 AM - 8:00 AM
11:00 AM - 11:00 PM.

Je sais pas si je suis bien clair et je suis même pas sûr que ca soit possible en SQL uniquement.

Avez vous une piste à me donner? (pas d'autres langages en renfort).

Merci d'avance,
Configuration: Linux
Firefox 3.0.8

8 réponses

  1. othanga
     
    bonjour,

    peut-être la solution viendrait-elle d'un truc du genre
    select debut, min(fin) from (
    select a.heure_de_fin as debut, b.heure_de_debut as fin
    from reservations a, reservations b
    where a.heure_de_fin < b.heure_de_debut
    union
    select :horaire_minimum as debut, b.heure_de_debut as fin
    from reserations
    union
    select heure_de_fin as debut, :horaire_maximum as fin
    ) resas
    group by debut

    les horaire_minimum et horaire_maximum seraient à remplacer par les 5:00 AM et 11:00 PM de ton exemple
    0
  2. d_laurent23 Messages postés 6 Statut Membre
     
    Bonsoir,
    Si tu traites tes résultats de manière itératives, tu dois pouvoir tester l'heure de fin de réservation du créneau à l'indice i et le comparer avec la valeur du début de la réservation qui l'a suit (si tu as un ORDER BY dans ta requête).

    Tiens-nous au courant.
    Cordialement,
    Laurent.
    0
    1. Noubli
       
      J'ai bien peur que le SQL de 'haut-niveau" me dépasse carément.
      0
  3. P@t@ch0n Messages postés 603 Statut Membre 85
     
    Hum, je suis pas bien certain d'avoir saisi, mais d'après ce que j'ai compris, je vois rien de sorcier là-dedans.

    SELECT heureDebutReservation, heureFinReservation 
    FROM reservation 
    WHERE ( heureDebutReservation BETWEEN creneauHeureDebut AND creneauHeureFin )
    OR ( heureFinReservation BETWEEN creneauHeureDebut AND creneauHeureFin);


    Bien évidemment il faut que les formats soient identiques.
    0
    1. Noubli
       
      Je vois pas bien ce que tu appelles creneauHeureDebut et creneauHeureFin dans ta requete :/
      0
  4. P@t@ch0n Messages postés 603 Statut Membre 85
     
    Par exemple, si j'ai une reservation entre 8:00 AM (creneauDebut) et 11:00 AM (creneauFin)
    0
  5. Vous n’avez pas trouvé la réponse que vous recherchez ?

    Posez votre question
  6. othanga
     
    re

    les créneaux début et fin dont parle p@t@chon sont en fait respectivement tes fin et début de réservation.
    => pour utiliser des zones nommées comme celles de p@t@chon, tu réalise une extraction de tes réservations (début créneau = fin réservation & fin créneau = début réservation suivante) que tu déverses dans une nouvelle table où tu vas pouvoir requêter sans souci.

    si tu ne peux ou ne veux pas introduire une table supplémentaire, tu requêtes des débuts et des fins de créneaux en prenant respectivement des fins et des débuts de réservation. Comme la fin de la réservation ne sera jamais antérieure au début figurant dans ta requête, tu es obligé d'interroger le produit réservations x réservations.
    À compter de ce moment, tu peux ne retenir que les lignes ou fin < début. Ce faisant, pour une fin, tu obtiens une multitude de débuts ultérieurs, il te suffit de prendre le plus petit.

    ex:
    dans la table RESA, tu as 4 réservations :
    R1 : ( 7h ; 9h ) -- de 7h à 9h
    R2 : ( 9h30 ; 11h )
    R3 : ( 12h ; 16h30 )
    R4 : ( 17h ; 22h )

    si tu requêtes RESA x RESA en demandant fin < debut
    (select a.fin, b.debut from RESA a, RESA b where a.fin < b.debut)
    alors tu obtiens :
    x1 : ( 9h ; 9h30 ) -- la fin de R1 avec le début de R2
    x2 : ( 9h ; 12h ) -- la fin de R1 avec le début de R3
    x3 : ( 9h ; 17h ) -- la fin de R1 avec le début de R4
    x4 : ( 11h ; 12h ) -- la fin de R2 avec le début de R3
    x5 : ( 11h ; 17h ) -- la fin de R2 avec le début de R4
    x6 : ( 16h30 ; 17h ) -- la fin de R3 avec le début de R4

    arrivés ici, il y a des trucs bien (x1 est bien un créneau) et d'autres qui vont pas du tout (x2 = créneau + résa)

    c'est là qu'intervient le second select, celui où l'on ne conserve le min(fin) pour chaque début
    (select fin, min(debut) from ce_que_je_viens_de_calculer group by fin)
    le min(fin) pour 9h => min(fin) dans x1, x2 & x3 => 9h30
    => ( 9h ; 9h30 )
    le min(fin) pour 11h => min(fin) dans x4 & x5 => 12h
    => ( 11h ; 12h )
    le min(fin) pour 16h30... vu qu'il n'y a qu'une combinaison, le choix est vite fait
    => ( 16h30 ; 17h )

    et voilà !
    tu as tes créneaux, tes plages non réservées, le tout en une requête.

    Elle est pas belle la vie ?
    0
  7. Noubli
     
    Super, c'est exactement ce que je voulais :).
    Merci beaucoup !!!!

    Il reste juste un hic, il n'y a pas dans cette technique les notions d'heure de début de possibilité de reservation et de fin de possibilité de reservation. (jsais pas si c'est clair).
    Par exemple :
    Dans ton exemple, si les reservations commencent à 5:00 AM, je voudrais qu'il y ai aussi une ligne :
    (5:00;7:00)
    (et idem pour la fin).
    Pour l'instant, j'ai reussi à m'en sortir en insérant une reservation qui commence et finit à 5:00 AM (de même pour la fin), mais ça m'a l'air un peu sale comme technique non? (bien sûr je l'efface à la fin de mon block de requête).

    En tout cas, merci beaucoup pour tes explications, c'était très clair.

    Noubli.
    0
  8. othanga
     
    effectivement, dans la démonstration détaillée, il n'y a pas les "créneaux" extrèmes.
    c'est pour ça que j'avais rajouté dans la 1ere requete présentée
    ...
    UNION
    SELECT :horaire_minimum as debut, b.heure_de_debut as fin
    FROM reservations
    UNION
    SELECT a.heure_de_fin as debut, :horaire_maximum as fin
    FROM reservations

    notons au passage que c'est pas pratique car le 1er union renvoie autant de lignes qu'il y a de RESA
    j'aurais du écrire :

    UNION
    SELECT :horaire_minimum as debut, MIN(b.heure_de_debut) as fin
    FROM reservations
    UNION
    SELECT MAX(a.heure_de_fin) as debut, :horaire_maximum as fin
    FROM reservations

    explication avec la demo:
    1. si tu remplaces horaire_minimum par 5h00, le 1er select te renvoie x0 : ( 5h00 ; 9h00 )
    2. si tu remplaces horaire_maximum par 23h00, le 2nd select te renvoie x7 : (17h00 ; 23h00)
    3. les UNION servent à rajouter les lignes x0 et x7 au résultat de ta requete initiale
    4. le second select de la demo (celui qui renvoie debut, min(fin)) renverra en plus de tes créneaux ces 2 lignes rajoutées (note au passage que comme il n'existe qu'une seule ligne pour 5h et une seule pour 17h, le group by est instantané)

    J'ai noté tes 5h et 23h sous forme de paramètre SQL, car aujourd'hui tu veux gérer de 5h à 23h.
    Si demain tu veux gérer de 7h à 20h, tu n'auras qu'à changer les paramètres d'appel de ta requête.
    Si par contre tu écris des constantes dans ta requête, il faudra que tu (ou ton remplaçant) aille retrouver la requête et la modifie avec les nouvelles valeurs

    Ça te va ?
    0
  9. Noubli
     
    Ah oui, effectivement, j'avais pas vu que c'était toi qui avait posté là-haut.
    Et je pense que cette dernière partie j'aurais pu la faire tout seul en y réfléchissant bien.

    Mais c'est là que je me rends compte que je suis assez nul en SQL.
    Ca serait indiscret de te demander combien d'années d'expérience tu as dans ce domaine?

    En tout cas merci beaucoup, c'est tout à fait ce dont j'avais besoin et j'ai pu bien comprendre avec tes explications, je mets le sujet en résolu.

    Merci encore,

    Noubli.
    0