Modélisation Base de donnée

ViPHP
ViPHP | 3607 Messages

15 sept. 2008, 12:28

Bonjour à tous,
J'ai un petit problème de modélisation aujourd'hui...
Je suis en train de créer un petit module de gestion de dates de spectacles pour un de mes sites,
J'ai donc créé une table

Code : Tout sélectionner

-- -- Structure de la table `agenda` -- CREATE TABLE `agenda` ( `id_evenement` int(11) NOT NULL auto_increment, `date_evenement` datetime NOT NULL, `fin_evenement` datetime NOT NULL, `description` varchar(200) collate utf8_bin NOT NULL, `codepostal` char(5) collate utf8_bin NOT NULL, `ville` varchar(70) collate utf8_bin NOT NULL, PRIMARY KEY (`id_evenement`) ) ENGINE=MyISAM DEFAULT CHARSET=utf8 COLLATE=utf8_bin AUTO_INCREMENT=8 ;
Rien de bien sorcier (même si il y peut-être déjà des bourdes :oops: )
Donc avec cette structure, je peux mettre une date "unique" en laissant le champ fin_evenement à zero, ou un évènement sur plusieurs jours, en renseignement les deux...
Seulement, il y a un cas qui me gène, c'est si je veux mettre trois dates pour le même spectacle du genre
Le 12, 15 et 23 septembre, blablala
J'ai deux solutions en tête:
~1 - Je cré une deuxième table spectacle, liée avec les dates....
Inconvénient, c'est un peu plus long à mettre en place, et je ne sais pas si c'est vraiment juste par rapport au modèle, parceque la plupart des spectacles seront avec une date unique, bref je sais pas trop
~2 - He rajoute un champ "liaison" dans ma table, et lorsque je souhaite lier plusieurs dates pour un spectacle, je remplis ce champ liaison via un uniqid() ou autre, et je peux ainsi récupérer le tout...

Voilà j'attend vos idées et point de vue sur la question...
Merci ;)

Modérateur PHPfrance
Modérateur PHPfrance | 2575 Messages

15 sept. 2008, 15:35

Le mieux est de mettre un champ nommé "dates_evenement" au lieu des deux champs "date_evenement" et "fin_evenement", pour enregistrer l'ensemble des dates d'un spectacle sous forme d'une chaine où les dates seront séparées par une virgule par exemple. Comme ça quand il s'agit d'un cas de spectacle se déroulant les 12, 15 et 23 septembre tu pourras écrire :

Code : Tout sélectionner

dates_evenement = '12/09/08,15/09/08,23/09/08'
Le type du champ dates_evenement est donc varchar(255)
Ce qui t'oblige à respecter ce format de séparation des dates par virgule l'or de l'ajout, modification et récupération des données.

Au niveau de l'opération de récupération des données de ce champ c'est simple, on peut utiliser les fonction split() ou explode() de PHP. Par exemple :
//Après exécution d'un SELECT SQL
$dates_evenement = explode("," , $row["dates_evenement"]);
//Récup. des dates
foreach($dates_evenement as $date) echo $date . "<br />";
--------//////----//---//----//////
-------//---//----//---//----//---//
------//////----//////-----//////
-----||--------||--||---||
Prendre le recul n'est pas une perte de temps.


ps: Affrontez moi dans l'arène

ViPHP
ViPHP | 3607 Messages

15 sept. 2008, 15:39

Mais euh....
Et comment je fait pour ordonner ma selection via la date...?
ça ira pas si c'est un varchar, si?
Je me demande de plus en plus si je vais pas faire deux tables...
Un autre problème dans ta manière de faire, comment différencier un spectacle qui se passe du tant au tant, d'un spectacle qui se passe le tant et le tant... Il faut encore rajouter un champ plage à 1 ou 0...

D'autres avis?

Mammouth du PHP | 1353 Messages

15 sept. 2008, 15:45

Bonjour,

Personnellement je ferai une table à part avec comme champ

Code : Tout sélectionner

CREATE TABLE `date_evenements` ( `id_date_evenement` int(11) NOT NULL auto_increment, `id_evenement` int(11) NOT NULL auto_increment, `date_evenement` datetime NOT NULL, `fin_evenement` datetime NOT NULL, PRIMARY KEY (`id_date_evenement`) ) ENGINE=MyISAM DEFAULT CHARSET=utf8 COLLATE=utf8_bin AUTO_INCREMENT=8 ;
C'est pas beaucoup plus long à faire et tu peux avoir les périodes ou les dates simples ou les deux selon que fin_evenement soit rempli ou pas par exemple, et avoir facilement toutes les dates/périodes pour un évènement donné...

De même tu pourras par exemple récupérer tous les évènements qui se jouent entre telle date et telle date, ce qui est moins facile avec une structure avec des varchar...
Tell me and I forget. Teach me and I remember. Involve me and I learn.

ViPHP
ViPHP | 3607 Messages

15 sept. 2008, 15:47

Vi je croit que ça sera le fin mot de l'histoire....
Si je reviendrais si j'ai des problèmes d'implémentation ;)
merci

ViPHP
ViPHP | 3607 Messages

25 sept. 2008, 00:03

Bonsoir,
alors je reviens demander de l'aide sur l'implémentation du bazar...
pour les tables et un jeu d'essai, c'est là:
table evenements

Code : Tout sélectionner

-- -- Structure de la table `evenements` -- CREATE TABLE IF NOT EXISTS `evenements` ( `id_evenement` int(11) NOT NULL auto_increment, `description` varchar(200) collate utf8_bin NOT NULL, `codepostal` char(5) collate utf8_bin NOT NULL, `ville` varchar(70) collate utf8_bin NOT NULL, PRIMARY KEY (`id_evenement`) ) ENGINE=MyISAM DEFAULT CHARSET=utf8 COLLATE=utf8_bin AUTO_INCREMENT=23 ; -- -- Contenu de la table `evenements` -- INSERT INTO `evenements` (`id_evenement`, `description`, `codepostal`, `ville`) VALUES (16, 'spectacle', '38000', 'beaurepaire'), (17, 'spectacle2', '26210', 'lens-lestang'), (18, 'spectacle3', '38000', 'grenoble'), (19, 'spectacle4', '69000', 'lyon'), (20, 'essai', '38000', 'grenoble'), (21, 'essai', '38000', 'grenoble'), (22, 'test2', '38000', 'grenoble');
et la table dates

Code : Tout sélectionner

-- -- Structure de la table `dates` -- CREATE TABLE IF NOT EXISTS `dates` ( `id_date` int(10) unsigned NOT NULL auto_increment, `id_evenement` int(10) unsigned NOT NULL, `date_debut` datetime NOT NULL, `date_fin` datetime NOT NULL, PRIMARY KEY (`id_date`) ) ENGINE=MyISAM DEFAULT CHARSET=utf8 COLLATE=utf8_bin AUTO_INCREMENT=11 ; -- -- Contenu de la table `dates` -- INSERT INTO `dates` (`id_date`, `id_evenement`, `date_debut`, `date_fin`) VALUES (1, 16, '2008-09-17 16:24:39', '0000-00-00 00:00:00'), (2, 16, '2008-09-17 16:31:55', '0000-00-00 00:00:00'), (3, 16, '2008-09-09 16:32:00', '0000-00-00 00:00:00'), (4, 17, '2008-09-25 19:27:07', '0000-00-00 00:00:00'), (5, 17, '2008-09-16 19:27:21', '0000-00-00 00:00:00'), (6, 18, '2008-09-19 11:51:39', '2008-09-26 11:51:43'), (7, 19, '2008-09-30 16:47:51', '0000-00-00 00:00:00'), (8, 20, '1987-06-11 20:30:00', '0000-00-00 00:00:00'), (9, 21, '1987-06-11 20:30:00', '0000-00-00 00:00:00'), (10, 22, '2008-12-20 20:30:00', '0000-00-00 00:00:00');
Bon alros je m'en vois un peu pour l'affichage des dates selon ce que je veux...
pour l'instant ça donne ça:
//requête sql

$sql=	"SELECT
			e.id_evenement as id,
			e.description as descri, 
			e.ville as ville, 
			e.codepostal as cp, 
			d.date_debut as dated, 
			d.date_fin as datef
		FROM 
			evenements AS e, 
			dates AS d
		WHERE 
			d.id_evenement = e.id_evenement
		ORDER BY 
			e.id_evenement,
			d.date_debut 
		DESC";
$resultats=$connexion->query($sql);

//instanciation de varibles pour le tri des résultats
$id_temp=null;
$i=0;

//boucle sur les résultats
while($rep= $resultats->fetch(PDO::FETCH_ASSOC)){

	//si on change d'évènement, on change d'index du tableau de résultats
	if($id_temp!==$rep['id']) {
		$i++;
		$res[$i]=array(
					'descri'=>$rep['descri'],
					'ville'=>$rep['ville'],
					'cp'=>$rep['cp'],
					'dateds'=>array($rep['dated']),
					'datefs'=>array($rep['datef'])
				);
	//sinon on ajoute juste les dates 
	} else {
		$res[$i]['dateds'][]=$rep['dated'];
		$res[$i]['datefs'][]=$rep['datef'];
	}
	$id_temp=$rep['id'];
}

// ensuite on retri, pour avoir les différents types de dates
// à savoir, 
//	plusieurs dates pour un évènement
//	une plage de date
//	une date unique (avec affichage de l'heure)
for($j=1;$j<=count($res);$j++){
	
	//si plusieurs dates, alors plage de date
	if(count($res[$j]['dateds'])>1){
	
		array_walk(
				$res[$j]['dateds'],
				create_function('&$v,$k', '$v =strftime("%e %B %Y", strtotime($v));')
		);
		$res[$j]['date']='Les '.implode(', ',$res[$j]['dateds']);
	
	//si une seule date et date de fin non renseignée, date unique
	} elseif( $res[$j]['datefs'][0]==='0000-00-00 00:00:00'){
	
		$res[$j]['date']='Le '.strftime("%e %B %Y",strtotime($res[$j]['dateds'][0]));
		$temp=explode(' ',$res[$j]['dateds'][0]);
		
		if($temp[1]!=='00:00:00')
			$res[$j]['date'].=' à '.strftime("%Hh%M",strtotime($res[$j]['dateds'][0]));
	
	//si une seule date et date de fin renseignée, plage de date
	} else {
	
		$res[$j]['date']='Du '.strftime("%e %B %Y",strtotime($res[$j]['dateds'][0])).' au '.strftime("%e %B %Y",strtotime($res[$j]['datefs'][0]));
		
	}
	
}
Le problème, c'est que je trouve ça vachement lourd, pour afficher quelques dates...
Et pour l'instant, l'affichage et simple, mais si je souhaite par exemple au lieu de dire:
Les 11 juin 2009, 13 juin 2009, 15 juillet 2009
Je souhaite avoir quelque chose genre
Les 11 et 13 Juin et le 15 Juillet 2009
ça va devenir de plus en plus lourd...
Alors ma question est, est-ce que je fonce droit dans le mur? ou est-ce que y a pas vraiment plus simple?

Eléphant du PHP | 254 Messages

25 sept. 2008, 01:01

- Euh pourquoi ne pas te servir de ton tableau de résultats directement plutôt que de le stocker dans un autre
- Pourquoi ne pas se servir de la fonction date() qui me semble plus lisible pour afficher ?

Modérateur PHPfrance
Modérateur PHPfrance | 2575 Messages

25 sept. 2008, 02:41

Voici une proposition qui d'abord repose sur SQL pour préparer des critères de classement par id événement et par date début. Comme ça on pourra dire avoir des ruptures de lots pour tel événement, et pour tant de dates par événement.
Voici donc la requête:
$sql = "SELECT
            e.id_evenement as id,
            e.description as descri, 
            e.ville as ville, 
            e.codepostal as cp, 
            d.date_debut as dated, 
            d.date_fin as datef
        FROM 
            evenements AS e 
	    join  
            dates AS d 
            on d.id_evenement = e.id_evenement
        ORDER BY 
            e.id_evenement, d.date_debut ASC";
En suite, c'est au rôle de PHP de classer dans un Array, les enregistrements reçus de SQL dument triés dans l'ordre de classement voulu. On peut utiliser pour ça un tableau associatif dont les index sont nommés par les critères de classement choisis dans SQL à savoir : id événement, et la date de début. Seulement on va décortiquer cette date en année, mois et jour pour regrouper les mêmes événements dans une seule case id, pour la mêmes année et le même mois et jour.
Voici comment créer un tel tableau à partir de la requête SQL:
$events = array();
while($resultats && $row = mysql_fetch_assoc($resultats))
{ 
	//Classement des événements par années/mois/jour 
	extract($row);
	$annee = (int)date('Y', strtotime($dated));
	$mois = (int)date('m', strtotime($dated));
	$jour = (int)date('d', strtotime($dated));
	$events[$id][$annee][$mois][$jour][] = $row;
}
En fait, PHP ne fait que reprendre l'ordre de tri fourni par SQL, et spécifie les champs comme index hiérarchisés dans le tableau pour éviter le dédoublement des lignes correspondant à ces index.
Par exemple, si on a 3 événements concernant l'id 1 la requête retournera 3 fois l'id 1 dans les enregistrements. Mais puisque PHP enregistre l'id comme index du tableau, le même id ne sera stocké qu'une fois.

Le reste du programme consiste à lire le tableau produit par l'ordre hiérarchique établie : c'est à dire par id de l'événement, par année, par mois et par jour. Et ainsi l'on peut formuler la fameuse phrase que notre ami souhaite :
L'événement n° 1 aura lieu Les 11 et 13 Juin et le 15 Juillet 2009

Voici le programme général:
<?php
//Texte SQL
$sql = "SELECT
            e.id_evenement as id,
            e.description as descri, 
            e.ville as ville, 
            e.codepostal as cp, 
            d.date_debut as dated, 
            d.date_fin as datef
        FROM 
            evenements AS e 
	    join  
            dates AS d 
            on d.id_evenement = e.id_evenement
        ORDER BY 
            e.id_evenement, d.date_debut ASC";
//Exec SQL
$resultats = mysql_db_query("test", $sql, mysql_connect("localhost", "root"));

//calendrier français
$mois_fr = array(1=>"Janvier", 2=>"Février", 3=>"Mars", 4=>"Avril", 5=>"Mai", 6=>"Juin", 
7=>"Juillet", 8=>"Août", 9=>"Septembre", 10=>"Octobre", 11=>"Novembre", 12=>"Décembre");

//Boucle sur les résultats
$events = array();
while($resultats && $row = mysql_fetch_assoc($resultats))
{ 
	//Classement des événements par années/mois/jour 
	extract($row);
	$annee = (int)date('Y', strtotime($dated));
	$mois = (int)date('m', strtotime($dated));
	$jour = (int)date('d', strtotime($dated));
	$events[$id][$annee][$mois][$jour][] = $row;
}

//Affichage
$event = "";
if (is_array($events) && count($events)>0)
{
  //début des id event  
  foreach($events as $id=>$idArray)
  {
	//début des années du même id event
	$event .= "L'événement $id aura lieu ";
	$a=0;
	foreach($idArray as $annee=>$anneesArray)
	{
		//début des mois de la même année
		$m=0;
		foreach($anneesArray as $mois=>$moisArray)
		{
			//début des jours du même mois
			$event .= count($moisArray)<=1?" le ":" les "; //+ écrit "le" ou "les" selon le nombre de jours event du mois
			$j=0;
			foreach($moisArray as $jour=>$dataEvent)
			{
				$event .= " <a href='#' onclick='show(" . json_encode($dataEvent) . ")'>$jour</a>" . ($j<count($moisArray)-2?", ":" et "); //+ remplace dernier "," par "et"
				$j++;
			}
			//fin des jours du même mois
		    $event = preg_replace('#(et)\s?$#i', ' ', $event); //+ remplace dernier "et" par " "
			$event .= $mois_fr[$mois] . ($m<count($anneesArray)-2?", ":" et "); //+ remplace dernier "," par "et"
			$m++;
		}
		//fin des mois de la même année
		$event = preg_replace('#(et)\s?$#i', ' ', $event); //+ remplace dernier "et" par " "
		$event .= " $annee" . ($a<count($idArray)-1?", ":" et "); //+ remplace dernier "," par "et"
		$a++;
	}
	//fin des années pour le même id
	$event = preg_replace('#(et)\s?$#i', ' ', $event); //+ remplace dernier "et" par " "
	$event .= "<br />";
  }
  //fin des id event
}
//
echo $event!=null?$event:"Aucun événement !";
?>
<div id="afficheur" style="width:200; height:150; background-color:yellow; color:blue; font-family:arial; font-size:small;"></div>
<script type="text/javascript"> 
//Afficher les données d'un objet jSon Array
function show(eventDataArray)
{
	var eventData = eventDataArray[0];
	document.getElementById("afficheur").innerHTML = '<h5>Evénement n°' + eventData.id + '</h5><hr>';
	document.getElementById("afficheur").innerHTML += '<p>Date: ' + eventData.dated + '</p>';
	document.getElementById("afficheur").innerHTML += '<p>Description: ' + eventData.descri + '</p>';
}
</script>
En supplément et en guise de finition, le script contient aussi des instructions qui déterminent quand il faut placer une "virgule" ou un "et" dans les phrases générées et des liens hypertextes sur les jours pour afficher le détail de l'event dans un div.

Et voici la base de test:

Code : Tout sélectionner

-- -- Structure de la table `dates` -- CREATE TABLE IF NOT EXISTS `dates` ( `id_date` int(10) unsigned NOT NULL auto_increment, `id_evenement` int(10) unsigned NOT NULL, `date_debut` datetime NOT NULL, `date_fin` datetime NOT NULL, PRIMARY KEY (`id_date`) ) ENGINE=MyISAM DEFAULT CHARSET=utf8 COLLATE=utf8_bin AUTO_INCREMENT=13 ; -- -- Contenu de la table `dates` -- REPLACE INTO `dates` (`id_date`, `id_evenement`, `date_debut`, `date_fin`) VALUES (1, 16, '2008-09-15 16:24:39', '0000-00-00 00:00:00'), (2, 16, '2008-09-17 16:31:55', '0000-00-00 00:00:00'), (3, 16, '2008-11-09 16:32:00', '0000-00-00 00:00:00'), (4, 17, '2008-09-25 19:27:07', '0000-00-00 00:00:00'), (5, 17, '2008-09-16 19:27:21', '0000-00-00 00:00:00'), (6, 18, '2008-09-19 11:51:39', '2008-09-26 11:51:43'), (7, 19, '2008-09-30 16:47:51', '0000-00-00 00:00:00'), (8, 20, '1987-06-11 20:30:00', '0000-00-00 00:00:00'), (9, 21, '1987-06-11 20:30:00', '0000-00-00 00:00:00'), (10, 22, '2008-12-20 20:30:00', '0000-00-00 00:00:00'), (11, 16, '2008-09-11 16:32:00', '0000-00-00 00:00:00'), (12, 16, '2009-01-12 00:00:00', '0000-00-00 00:00:00'), (13, 16, '2009-01-20 00:00:00', '0000-00-00 00:00:00'), (14, 16, '2009-03-15 00:00:00', '0000-00-00 00:00:00'); -- -------------------------------------------------------- -- -- Structure de la table `evenements` -- CREATE TABLE IF NOT EXISTS `evenements` ( `id_evenement` int(11) NOT NULL auto_increment, `description` varchar(200) collate utf8_bin NOT NULL, `codepostal` char(5) collate utf8_bin NOT NULL, `ville` varchar(70) collate utf8_bin NOT NULL, PRIMARY KEY (`id_evenement`) ) ENGINE=MyISAM DEFAULT CHARSET=utf8 COLLATE=utf8_bin AUTO_INCREMENT=23 ; -- -- Contenu de la table `evenements` -- REPLACE INTO `evenements` (`id_evenement`, `description`, `codepostal`, `ville`) VALUES (16, 'spectacle', '38000', 'beaurepaire'), (17, 'spectacle2', '26210', 'lens-lestang'), (18, 'spectacle3', '38000', 'grenoble'), (19, 'spectacle4', '69000', 'lyon'), (20, 'essai', '38000', 'grenoble'), (21, 'essai', '38000', 'grenoble'), (22, 'test2', '38000', 'grenoble');
--------//////----//---//----//////
-------//---//----//---//----//---//
------//////----//////-----//////
-----||--------||--||---||
Prendre le recul n'est pas une perte de temps.


ps: Affrontez moi dans l'arène

ViPHP
ViPHP | 3607 Messages

25 sept. 2008, 10:26

Merci merci pour ton aide!!
J'ai pas trop compris la différence entre ta requête et la mienne...
ça reste lourd tout de même pfff mais bon je me rend à l'évidence, il n'y a que cette solution...
Je viens de me rendre compte d'un autre problème...
J'ai à faire un tri sur la date de début ou sur la date de fin...
Je m'explique, je classe les évènement en deux parties:
->Ceux qui ont au moins soit une date unique, soit une fin de plage qui est supèrieure à aujourd'hui
->Ceux dont toutes les dates sont passées

et ça me parait difficile de faire ça en mysql, j'ai essayer, mais ça me retourne des erreurs, et je vois pas comment faire...
Donc ça veut dire que dans mes deux pages séparées, je vais devoir selectionner tout le jeux de dates, puis squizzer une partie?
En écrivant ces mots je pense également à faire une pagination, qui risque d'être difficile, il faudra arriver à la palce de faire un LIMIT n,10 à compter les ids évènements différents afin d'arrêter la requête à 10 évènements!!!
Houlà ça commence à me donner mal à la tête...[/code]

Modérateur PHPfrance
Modérateur PHPfrance | 2575 Messages

25 sept. 2008, 16:44

C'est sûr que si tu continues à sauter d'un besoin à un autre sans fil conducteur tu vas non seulement avoir mal à la tété mais aussi te décourager. |*()

Et ce n'est pas en disant, ceci est dur ou cela est compliqué que tu vas faire des choses biens. C'est ton programme, retrousse les manches et vas-y fonce ! :ordi:

Mais petit à petit, jalon par jalon, il faut savoir terminer ce que l'on commence. Chi va piano, va sano e va lontano.

Allez courage !
--------//////----//---//----//////
-------//---//----//---//----//---//
------//////----//////-----//////
-----||--------||--||---||
Prendre le recul n'est pas une perte de temps.


ps: Affrontez moi dans l'arène

ViPHP
ViPHP | 3607 Messages

02 oct. 2008, 12:33

Alors tout d'abord merci merci!
Car grace à ton idée, je commence à voir le bout de mes peines ;)
Je voulais juste savoir votre avis sur une petite idée...

Pour rerésumer, je souhaite afficher d'un côté les évènements "dont toutes les dates sont passées" et de l'autres le reste...
Sachant que sur la deuxième catégorie, je n'aurait jamais de pagination à faire et tout le toutime, parce qu'une compagnie de cirque n'aura jamais plus de 30 dates sûre d'avance :langue:
Donc je souhaitais me faciliter la tache sur les "anciennes dates",
et j'avais pensé à rajouter un champ "old" sur l'évènement qui serait un booléen pour dire si c'est une ancienne date ou non...
Je pourrait ainsi faire des limit sur le nombre d 'évènement passés...
Après il faut que je mette soit un cron soit que le premier utilisateur déclenche la mise à jour de ce champ...
Votre avis une meilleur idée?
merci d'avance!!

Modérateur PHPfrance
Modérateur PHPfrance | 2575 Messages

02 oct. 2008, 14:44

T'as pas besoin de marquer les anciens, car la requête SQL peut le faire aisément. Il suffit d'ajouter un critère qui compare la date de fin de l'événement à la date du jour.

Voici comment :
Requête qui extrait les événements passés:
$sql = "SELECT
            e.id_evenement as id,
            e.description as descri, 
            e.ville as ville, 
            e.codepostal as cp, 
            d.date_debut as dated, 
            d.date_fin as datef
        FROM 
            evenements AS e 
        join  
            dates AS d 
            on d.id_evenement = e.id_evenement
        WHERE d.date_fin < Now()
        ORDER BY 
            e.id_evenement, d.date_debut DESC"; 

Requête qui extrait les événements à venir ou en cours:
$sql = "SELECT
            e.id_evenement as id,
            e.description as descri, 
            e.ville as ville, 
            e.codepostal as cp, 
            d.date_debut as dated, 
            d.date_fin as datef
        FROM 
            evenements AS e 
        join  
            dates AS d 
            on d.id_evenement = e.id_evenement
        WHERE d.date_fin >= Now()
        ORDER BY 
            e.id_evenement, d.date_debut ASC"; 
--------//////----//---//----//////
-------//---//----//---//----//---//
------//////----//////-----//////
-----||--------||--||---||
Prendre le recul n'est pas une perte de temps.


ps: Affrontez moi dans l'arène

ViPHP
ViPHP | 3607 Messages

02 oct. 2008, 14:58

C'est un peu plus compliqué que ça...
Mais tu m'as mis sur la voie... voici une requête qui fonctionne à priori:

Code : Tout sélectionner

SELECT e.id_evenement AS id, e.description AS descri, e.ville AS ville, e.codepostal AS cp, d.date_debut AS dated, d.date_fin AS datef FROM evenements AS e JOIN dates AS d ON d.id_evenement = e.id_evenement WHERE d.id_evenement IN ( SELECT e.id_evenement FROM evenements AS e JOIN dates AS d ON d.id_evenement = e.id_evenement WHERE d.date_fin >= Now( ) OR d.date_debut >= Now( ) ) ORDER BY e.id_evenement, d.date_debut ASC
Je suis obligé de faire une sous-requête afin de récupérer les ids des évènements qui ont "au moins une date (soit de fin soit une date de début) supèrieure à now()", afin de pouvoir ensuite récupérer les autres dates liées à cet évènement, qu'elles soient périmées ou non...
Mais je me pose encore une question...
Comment faire des traitements genre LIMIT sur les évènements, sachant que j'ai plusieurs ligen par évènement?

Modérateur PHPfrance
Modérateur PHPfrance | 2575 Messages

02 oct. 2008, 15:44

Quand on a un JOIN dans un SELECT on n'a pas besoin de IN pour faire la même chose.

Je m'explique:
Il y a deux forme pour exprimer la jointure naturelle (Intersection) selon le modèle relationnel: La forme prédicative et la forme ensembliste.

1. La jointure naturelle prédicative où l'on connait la formule relationnelle entre 2 tables qui est sous la forme : clé primaire = clé étrangère.
En SQL, cette forme est notée en 2 manières :
  • a. Avec l'opérateur JOIN dans la clause FROM. Comme:

    Code : Tout sélectionner

    SELECT ... FROM table1 JOIN table2 ON table1.cléEtrangère = table2.cléPrimaire
    b. Avec un critère de sélection dans la clause WHERE. Comme :

    Code : Tout sélectionner

    SELECT ... FROM table1, table2 WHERE table1.cléEtrangère = table2.cléPrimaire
2. La jointure naturelle ensembliste où l'on recherche l'intersection par sous-sélection. Ce qui implique l'opérateur ensembliste IN et impose son usage dans la clause WHERE appropriée à la recherche. Comme:

Code : Tout sélectionner

SELECT ... FROM table1 WHERE table1.cléEtrangère IN ( SELECT table2.cléPrimaire FROM table2)
Revenons maintenant à ta requête :

Code : Tout sélectionner

SELECT e.id_evenement AS id, e.description AS descri, e.ville AS ville, e.codepostal AS cp, d.date_debut AS dated, d.date_fin AS datef FROM evenements AS e JOIN dates AS d ON d.id_evenement = e.id_evenement WHERE d.id_evenement IN ( SELECT e.id_evenement FROM evenements AS e JOIN dates AS d ON d.id_evenement = e.id_evenement WHERE d.date_fin >= Now() OR d.date_debut >= Now() ) ORDER BY e.id_evenement, d.date_debut ASC
On voit que tu utilise une double jointure naturelle : JOIN et IN ce qui n'est pas formellement bon car c'est une redondance.
Et si l'on considère que la méthode prédicative avec JOIN est la plus appropriée au modèle relationnelle et évite de déployer une requête imbriquée, ta requête redevienne:

Code : Tout sélectionner

SELECT e.id_evenement AS id, e.description AS descri, e.ville AS ville, e.codepostal AS cp, d.date_debut AS dated, d.date_fin AS datef FROM evenements AS e JOIN dates AS d ON d.id_evenement = e.id_evenement WHERE d.date_fin >= Now() OR d.date_debut >= Now() ORDER BY e.id_evenement, d.date_debut ASC
Par ailleurs, si l'on regarde bien le critère de sélection par date d'événement dans le WHERE, on constate que la formule :

Code : Tout sélectionner

d.date_fin >= Now() OR d.date_debut >= Now()
peut être simplifiée en :

Code : Tout sélectionner

d.date_fin >= Now()
Puisque si la date de fin d'un événement n'est pas dépassée alors quelque soit la date de début au passé ou au futur, l'événement est soit en cours soit prévu au futur.

Pour la question de la limite d'extraction de lignes, tu peux rajouter la clause LIMIT à la fin du SELECT. (voir ici : http://www.vulgarisation-informatique.c ... select.php)
Modifié en dernier par sadeq le 02 oct. 2008, 16:03, modifié 1 fois.
--------//////----//---//----//////
-------//---//----//---//----//---//
------//////----//////-----//////
-----||--------||--||---||
Prendre le recul n'est pas une perte de temps.


ps: Affrontez moi dans l'arène

ViPHP
ViPHP | 3607 Messages

02 oct. 2008, 15:59

Oui mais non.... :?
Et si l'on considère que la méthode prédicative avec JOIN est la plus appropriée au modèle relationnelle et évite de déployer une requête imbriquée, ta requête redevienne:
parceque ta requête, me retourne moins d'enregistrements que la mienne...
Imaginons que j'ai un évènement a qui est associé trois dates, dont deux passées, mais une encore à venir...
Je veux que cet évènement soit conté dans les évènements à venir, mais avec toutes ses dates, il faut donc en premier lieu que je récupère sont id, et ensuite que j'aille récupérer toutes ses dates, il y a peut-être d'autres, façon, mais en tout cas ta requête ne me convient pas... ensuite:
Concernant le WHERE, je ne peux pas simplifier, car la date de fin d'un évènement n'est pas forcément renseignée, donc peut-être égale à 0!
Mais ça ne pose pas trop de problème...

Concernant le LIMIT maintenant, je voudrais bien que ce soit aussi simple, mais pour reformuler mon problème,
si je veux avoir les 10 derniers évènement, je ne peux pas faire un LIMIT 0,10 sur ma requêtes, car elle me retourne plus de lignes qu'il n'y a d'évènement si ces derniers comportent plusieurs dates...

Je sais pas si je suis très clair dans mes explications, mais j'espère que tu as un peu mieux compris mes petits soucis, et que tu seras surement à même de m'aider
:D
merci encore en tout cas!