Table avec jointure

Eléphant du PHP | 89 Messages

10 janv. 2025, 16:08

Bonjour à Toutes et à Tous,

Permettez moi de vous souhaiter une excellente année 2025

Mon problème est le suivant:

Mon projet est une réservation de chambre d'hôtel (ou Gite) je sais faire une requête en mono table mais jamais fait avec jointure
(la requête à été prise sur un exemple que j'ai modifiée)

2 Tables :
1- Chambre id, numerochambre, codechambre, personne, typechambre, salledebain, salledebain, prix, photo01, photo03, photo03, photo04
2-Réservation id, codechambre, numerochambre, numeroreservation, datereservation, datearrivee , datedepart, nombrenuit, adulte, enfant, personne, typechambre, salledebain, prix

Chambre : 5 Chambres(pour l'instant) N° 1 à 5 du N° 1 à 4 codechambre = 2, chambre 5 codechambre=3
Réservation :
Chambre 1 du 2025-02-09 au 2025-02-10 (1)
Chambre 2 du 2025-02-09 au 2025-02-14 (5)
Chambre 3 du 2025-02-09 au 2025-02-10 (1)
Chambre 4 Libre
Chambre 5 du 2025-02-09 au 2025-02-10 (1)

$daterecherchee = '2025-02-09';
$daterechercheefin = '2025-02-10';

Code : Tout sélectionner

$reponse02 =$bdd->prepare('SELECT chambre.numerochambre, reservation.numerochambre FROM chambre INNER JOIN reservation ON chambre.numerochambre = reservation.numerochambre WHERE reservation.datearrivee = "'.$daterecherchee.'" GROUP BY numeroreservation ORDER BY reservation.numerochambre ASC'); $reponse02->execute(); $nb_reservation = $reponse02->rowCount(); echo '<p>Nbre Chambre(s) libre : '.$nb_reservation.'</p>'; while ($donnees02 = $reponse02->fetch()) { echo'<div class="col-3 bg-success"><span class="titre">Chambre Libre </span>'.$donnees02['numerochambre'].'</div>'; }
voici le résultat obtenu : apparemment l'inverse Nbre Chambre(s) libre : 4
Chambre Libre 1
1 / 2025-02-09 / 2025-02-10
Chambre Libre 2
2 / 2025-02-09 / 2025-02-10
Chambre Libre 3
3 / 2025-02-09 / 2025-02-10
Chambre Libre 5
5 / 2025-02-09 / 2025-02-10

La chambre 4 n'apparait pas


si vous pouvez m'aider ce serai super pour moi
Merci

Avatar du membre
Mammouth du PHP | 1530 Messages

11 janv. 2025, 02:19

Salut, merci, bonne année à toi également.

Le mieux est de faire une LEFT JOIN pour récupérer toutes les chambres puis les filtrer :
$reponse02 = $bdd->prepare("
    SELECT chambre.numerochambre
    FROM chambre
    LEFT JOIN reservation 
    ON chambre.numerochambre = reservation.numerochambre
    AND (
        (:daterecherchee BETWEEN reservation.datearrivee AND reservation.datedepart)
        OR (:daterechercheefin BETWEEN reservation.datearrivee AND reservation.datedepart)
        OR (reservation.datearrivee BETWEEN :daterecherchee AND :daterechercheefin)
    )
    WHERE reservation.numerochambre IS NULL
    ORDER BY chambre.numerochambre ASC
");

$reponse02->execute([
    'daterecherchee' => $daterecherchee,
    'daterechercheefin' => $daterechercheefin
]);
La recherche avec BETWEEN sera plus efficace (plus sûre) pour avoir les chambre qui sont réservées suivant leur date, car ta recherche pourrait inclure des chambres réservées le jour après $daterecherchee, et la réservation peut aussi commencer avant la période recherchée.

WHERE reservation.numerochambre IS NULL : Filtre les chambres qui n'ont pas de réservation sur la période recherchée.

Essaie déjà ça. :D

Eléphant du PHP | 89 Messages

11 janv. 2025, 12:08

Bonjour two3d,

Merci beaucoup pour ta réponse

Je connais les requêtes avec une seule table mais je n'ai jamais utilisé une jointure

Je me suis empressé de tester ta solution :
Il me sort la chambre qui n'est pas occupée à aucune date

Nbre Chambre(s) libre : 1
Chambre Libre 4
4 / 2025-02-10 / 2025-02-13

$daterecherchee = '2025-02-06';
$daterechercheefin = '2025-02-07';
il me sort les 5 chambres : OK

$daterecherchee = '2025-02-08';
$daterechercheefin = '2025-02-09';
Nbre Chambre(s) libre : 1
Chambre Libre 4
4 / 2025-02-08 / 2025-02-09 alors que toutes les chambres sont libres à cette date

Merci de te pencher sur mon problème

J'essaie ce code et je te tiens au courant, je fais des tests

Code : Tout sélectionner

$daterecherchee = '2025-02-12'; $daterechercheefin = '2025-02-14'; $daterechercheefin = strtotime($daterechercheefin); $daterechercheefin = date('Y-m-d', strtotime('-1 days',$daterechercheefin)); // 100422

Eléphant du PHP | 89 Messages

11 janv. 2025, 15:23

Bonjour à Tous

$daterecherchee = '2025-02-08';
$daterechercheefin = '2025-02-09';

Code : Tout sélectionner

$daterechercheefin = strtotime($daterechercheefin); $daterechercheefin = date('Y-m-d', strtotime('-1 days',$daterechercheefin));
j'ai bien :
Nbre Chambre(s) libre : 5
Chambre Libre N° 1
1 / 2025-02-08 / 2025-02-08
Chambre Libre N° 2
2 / 2025-02-08 / 2025-02-08
Chambre Libre N° 3
3 / 2025-02-08 / 2025-02-08
Chambre Libre N° 4
4 / 2025-02-08 / 2025-02-08
Chambre Libre N° 5
5 / 2025-02-08 / 2025-02-08

Mais si je mets la date d'arrivée le 10(jour de sortie il ne me reste que la chambre 4 qui n'est louée à aucun moment (normal)
J'ai l'impression que la date de départ entre en collision avec la date recherchée


peut-être :

Code : Tout sélectionner

$reponse02->execute([ 'daterecherchee' => $daterecherchee, 'daterechercheefin' => $daterechercheefin ]);
et moi je rajoute

Code : Tout sélectionner

$reponse02->execute([ 'daterecherchee' => $daterecherchee, 'daterechercheefin' => $daterechercheefin ]); $reponse02->execute(); $nb_reservation = $reponse02->rowCount(); echo '<p>Nbre Chambre(s) libre : '.$nb_reservation.'</p>'; while ($donnees02 = $reponse02->fetch()) { echo'<div class="col-3 bg-success"><span class="titre">Chambre Libre N° </span>'.$donnees02['numerochambre'].'</div>'; echo $donnees02['numerochambre'].' / '.$daterecherchee.' / '.$daterechercheefinnormale.'</br>'; }
Merci
Modifié en dernier par bernard25 le 11 janv. 2025, 15:45, modifié 1 fois.

Avatar du membre
Mammouth du PHP | 1530 Messages

11 janv. 2025, 15:24

Avec plaisir.

Avant d'aller plus loin, quel est le format de tes colonnes dates ?

Eléphant du PHP | 89 Messages

12 janv. 2025, 12:02

Bonjour two3d,
Merci de t'intéresser à mon problème, les champs dates sont de type date

pour info j'enregistre chaque jour de réservation pour une chambre occupée ex: le client ayant la chambre 2 loue du 2025-02-09 au 2025-02-14 j'ai un enregistrement datearrivee pour le 2025-02-09 / 2025-02-10/2025-02-11/2025-02-12/2025-02-13 et le numéro de réservation est identique pour le module comptabilité un seul enregistrement
Ta requête fonctionne très bien pour les jours n'ayant pas de réservation
Merci

Avatar du membre
Mammouth du PHP | 1530 Messages

12 janv. 2025, 13:33

OK, le moins compliqué serait d'enregistrer date_arrivee et date_depart (inutile de mettre tous les jours, seulement une pour l'arrivée et une pour le départ), et tu pourra faire une condition plus simple :
$reponse02 = $bdd->prepare("
	SELECT
		chambre.numerochambre
		#sélectionne ici ce que tu as besoin
		
	FROM
		chambre
		
	LEFT JOIN
		reservation 
		ON
			chambre.numerochambre = reservation.numerochambre
			AND
			reservation.date_arrivee >= '$date_arrivee'
			AND
			reservation.date_depart <= '$date_depart'
			
	WHERE
		reservation.numerochambre IS NULL
	
	ORDER BY
		chambre.numerochambre ASC
");

Avatar du membre
Mammouth du PHP | 1530 Messages

12 janv. 2025, 13:52

Si tu veux garder ta même logique d'enregistrer chaque date, il te faudra faire une recherche sur tous les jours réservés (rien de sûr ceci dit, cette solution me parait bancale) :
// défini la date de début et la date de fin
$dateDebut = new DateTime($daterecherchee);
$dateFin = new DateTime($daterechercheefin);

// ajoute 1 jour pour inclure le dernier jour dans la période
$dateFin->modify('+1 day');

// crée l'intervalle d'un jour
$interval = new DateInterval('P1D');

// crée une période
$periode = new DatePeriod($dateDebut, $interval, $dateFin);

// préparation de la requête
$requete = '';

// parcours et inclus chaque jour dans ta requête
foreach ($periode as $date) {
	$requete .= " AND reservation.datearrivee = '{$date->format('Y-m-d')}'";
}

var_dump($requete);

Eléphant du PHP | 89 Messages

12 janv. 2025, 15:51

Merci beaucoup,

Je me suis empressé de tester ta requête qui.... magnifique

Je me suis permis de modifier comme ceci :

Code : Tout sélectionner

$reponse02 = $bdd->prepare(" SELECT chambre.numerochambre FROM chambre LEFT JOIN reservation ON chambre.numerochambre = reservation.numerochambre AND reservation.datearrivee[u] =[/u][b] '".$daterecherchee."'[/b] AND reservation.datedepart <=[b] '".$daterechercheefin."'[/b] WHERE reservation.numerochambre IS NULL ORDER BY chambre.numerochambre ASC");
si daterecherchee reservation.datearrivee >= '".$daterecherchee."' ne trouve pas les dates antérieures, avec = cela fonctionne super daterecherchee = datearrivee n'affiche que les chambres non louées OK
daterecherchee > datearrivee n'affiche que les chambres non louées OK
daterecherchee < datearrivee n'affiche que les chambres non louées OK

Peux-tu me dire si ma "logique" est bonne

Un grand merci, Chapeau Bas

Avatar du membre
Mammouth du PHP | 1530 Messages

12 janv. 2025, 16:04

Oui, c'est bon, tant que tu vérifie "si ET si", soit "date arrivée ET date de fin" ne sont pas déjà prises (y compris les jours entres), OK.

Tu peux passer en résolu, n'hésites pas si tu as besoin d'autre chose, je peux également me demander un devis gratuit pour tes futurs travaux web, via mon site. :wink:

Eléphant du PHP | 89 Messages

12 janv. 2025, 16:52

Merci pour le temps passé,

2ème problème:
dans la même veine, le client choisi ses dates et Nombre Adulte et Nombre Enfant les chambres sont classées par contenance
codechambre = 1 (Chambre Simple)
codechambre = 2 (Chambre Double)
codechambre = 3 (Double + Lit Enfant)
Je dois proposer uniquement les chambres correspondant au nombre de personnes et à la date
en essayant de suite ta requête précédente j'ai fait : AND chambre.codechambre = reservation.codechambre

Code : Tout sélectionner

$reponse02 = $bdd->prepare(" SELECT chambre.numerochambre FROM chambre LEFT JOIN reservation ON chambre.numerochambre = reservation.numerochambre AND chambre.codechambre = reservation.codechambre AND reservation.datearrivee = '".$daterecherchee."' AND reservation.datedepart <= '".$daterechercheefin."' WHERE reservation.numerochambre IS NULL ORDER BY chambre.numerochambre ASC");
Ais-je fait une erreur car cela ne fonctionne pas
Merci mes travaux WEB sont pour l'instant "Fictifs" j'ai déjà fait quelques sites (en ligne) pour commerçants et cela à titre entièrement en bénévolat
Cela fait plus d'une semaine que je galère mais avec ta requête, cela devient plus limpide pour moi
Encore Merci

Avatar du membre
Mammouth du PHP | 1530 Messages

12 janv. 2025, 17:38

Écris ta requête avec des sauts de lignes pour facilité la lecture :
$reponse02 = $bdd->prepare("
  SELECT
		chambre.numerochambre
	
	FROM
		chambre
	
	LEFT JOIN
		reservation
		ON
		chambre.numerochambre = reservation.numerochambre
		AND
		chambre.codechambre = reservation.codechambre
		AND
		reservation.datearrivee = '".$daterecherchee."'
		AND
		reservation.datedepart <= '".$daterechercheefin."'
	
	WHERE
		reservation.numerochambre IS NULL
	
	ORDER BY
		chambre.numerochambre ASC
");
je vois que tu as mis = au lieu de >= à
reservation.datearrivee = '".$daterecherchee."'
C'est pas bon, il te faut impérativement >=, et pas =.

Ensuite, je pense qu'il te faudra une deuxième requête, while celle-ci, en prenant soin de SELECT les autres colonnes nécessaire au futur traitement, en plus de "chambre.numerochambre", puis fait un while.

Si tu souhaite faire en 1 requête, il te faut ajouter une condition à WHERE (à adapter à tes colonnes bien sûr) :
$reponse02 = $bdd->prepare("
	SELECT
		chambre.numerochambre
	
	FROM
		chambre
	
	LEFT JOIN
		reservation
		ON
		chambre.numerochambre = reservation.numerochambre
		AND
		chambre.codechambre = reservation.codechambre
		AND
		reservation.datearrivee >= '".$daterecherchee."'
		AND
		reservation.datedepart <= '".$daterechercheefin."'
	
	WHERE
		reservation.numerochambre IS NULL
		AND
		chambre.places >= '$nombre_de_place_recherchees'
	
	ORDER BY
		chambre.numerochambre ASC
");

Eléphant du PHP | 89 Messages

13 janv. 2025, 17:32

Bonjour two3d,
Merci j'ai remis le >= à ta requête mais il me sort:
Date Recherchée : 10/02/2025 Date Départ : 11/02/2025

Nbre Chambre(s) libre : 5
Chambre Libre N° 1
N° Chambre 1 / Date Recherchée 2025-02-10 / Date Départ 2025-02-11
Chambre Libre N° 2
N° Chambre 2 / Date Recherchée 2025-02-10 / Date Départ 2025-02-11
Chambre Libre N° 3
N° Chambre 3 / Date Recherchée 2025-02-10 / Date Départ 2025-02-11
Chambre Libre N° 4
N° Chambre 4 / Date Recherchée 2025-02-10 / Date Départ 2025-02-11
Chambre Libre N° 5
N° Chambre 5 / Date Recherchée 2025-02-10 / Date Départ 2025-02-11
OK pour toutes les chambres sauf la 2 qui est louée du 2025-02-09 au 2025-02-13 date de départ: 2025-02-14
Je ne comprends pas

concernant la 2ème demande (2ème requête)

Code : Tout sélectionner

$reponse02 = $bdd->prepare("SELECT chambre.numerochambre FROM chambre LEFT JOIN reservation ON chambre.numerochambre = reservation.numerochambre AND chambre.codechambre = reservation.codechambre AND reservation.datearrivee >= '".$daterecherchee."' AND reservation.datedepart <= '".$daterechercheefin."' WHERE reservation.numerochambre IS NULL AND chambre.codechambre = '".$codechambrerecherchee."' ORDER BY chambre.numerochambre ASC"); $reponse00 = $bdd->prepare('SELECT * FROM '.$reservation_BDD.' WHERE codechambre = '.$codechambrerecherchee.' ORDER BY id ASC'); $reponse00->execute(); $reponse02->execute(); $nb_reservation = $reponse02->rowCount(); echo '<p>Nbre Chambre(s) libre : '.$nb_reservation.'</p>'; while ($donnees02 = $reponse02->fetch()) { while ($donnees00 = $reponse00->fetch()){ $codechambre = $donnees00['codechambre']; } echo'<div class="col-3 bg-success"><span class="titre">Chambre Libre N° </span>'.$donnees02['numerochambre'].'</div>'; echo 'N° Chambre '.$donnees02['numerochambre'].' / Date Recherchée '.$daterecherchee.' / Date Départ '.$daterechercheefinnormale.' / Code Chambre '.$codechambre.'</br>'; }
avec 2 requêtes cela fonctionne

Avatar du membre
Mammouth du PHP | 1530 Messages

13 janv. 2025, 18:36

OK, avec deux requêtes c'est parfois plus simple, plus clair.

Je vois que tu mets tes dates 10/02/2025 et 2025-02-10 dans ton post, attention, MySQL prends le format 2025-02-10 jusqu'à preuve du contraire. :D

Eléphant du PHP | 89 Messages

14 janv. 2025, 15:13

Bonjour two3d,

Effectivement j'ai mis les dates en Français: Date Recherchée : 10/02/2025 Date Départ : 11/02/2025

mais j'utilise le format "anglais" dans la base de données et pour le traitement

Merci