[SQL] selection d'une liste par une requete - selection avec condition MySQL 5.0

Bonjour,

Etant débutant en SQL, je vous pose une question,

j’ai une Table students et une table logaccess.

Je veux sélectionner tous mes students.idbadge selon une condition particulière.

Explication : dans ma table logaccess j’ai des idbadgetype INT et un horodate type TIMESTAMP.

Je veux afficher dans une view (je suis en mySQL 5.0)

col1 idbadge et col2 horodate

Dans ma col1 je veux tous les students.idbadge avec dans col2 leurs logaccess.horodate correspondants.

Mais pour les étudiants qui n’ont pas de horodate…ben je veux afficher un NULL est ce possible ?

DROP VIEW IF EXISTS `badge_log`.`vw_test`;
CREATE ALGORITHM=UNDEFINED DEFINER=`root`@`localhost` SQL SECURITY DEFINER VIEW `vw_test` AS select sql_no_cache `students`.`idbadge` AS `idbadge`,cast(`logaccess`.`horodate` as date) AS `date` from `students`,`logaccess` WHERE `logaccess`.`idbadge`=`students`.`idbadge`;

Dans mon WHERE je sais pas quoi utilisé car ici je ne selection que ceux qui ont un horodate dans logaccess.

Voici une exemple graphique de ce que je veux faire :

±-----------------±-----------+
/ idbadge / horodate /
±-----------------±-----------+
/ 1 / 2006-01-02
/ 2 / NULL
/ 3 / NULL
/ 4 / 2006-02-07

Tu peux essayer de rajouter un UNION à ta requête.

CREATE ALGORITHM=UNDEFINED DEFINER=`root`@`localhost` SQL SECURITY DEFINER VIEW `vw_test` AS select sql_no_cache `students`.`idbadge` AS `idbadge`,cast(`logaccess`.`horodate` as date) AS `date` from `students`,`logaccess` WHERE `logaccess`.`idbadge`=`students`.`idbadge`
UNION
select `students`.`idbadge` AS `idbadge`, NULL AS `date` from `students` WHERE `idbadge` NOT IN (SELECT `idbadge` from `logaccess`)

merci asbel, je viens d’essayer, ca marche. :clap:

Maintenant a partir de la je vais corser la requete. Y aurais t’il pas moyen d’alleger ta requete ?

Tu veux dire l’alléger visuellement, ou pour le serveur ?

À première vue, que ce soit pour l’un ou l’autre, je ne vois pas… mais il y a peut-être effectivement moyen de faire plus simple / plus léger,

Pour le côte visuel, avec quelques saut de ligne, la mise en majuscule des mots clefs du langage, ça devrait aller.

Voici mon nouveau code

DROP VIEW IF EXISTS `badge_log`.`vw_test`;
CREATE ALGORITHM=UNDEFINED DEFINER=`root`@`localhost` SQL SECURITY DEFINER VIEW `vw_test` AS select sql_no_cache cast(`logaccess`.`horodate` as date) AS `date`,`students`.`idbadge` AS `idbadge`,`students`.`idgroups` AS `groupname`,`students`.`lastname` AS `lastname`,`students`.`firstname` AS `firstname`  from `students`,`logaccess` WHERE `logaccess`.`idbadge`=`students`.`idbadge`
UNION
select  NULL AS `date` ,`students`.`idbadge` AS `idbadge`,`students`.`idgroups` AS `groupname`,`students`.`lastname` AS `lastname` ,`students`.`firstname` AS `firstname`from `students` WHERE `idbadge` NOT IN (SELECT `idbadge` from `logaccess`)

Voici le résultat en image :slight_smile:
http://img207.imageshack.us/img207/4972/vwtest8fm.th.jpg

Ceci marche sans problème.

Par contre je veux rajouter une colonne à ma view ‘physical’

Elle fait ceci :

timediff(max(`logaccess`.`horodate`),min(`logaccess`.`horodate`)) AS `physical`

Donc j’ai codé ceci, sur la syntaxe tout me parait bon :??:

DROP VIEW IF EXISTS `badge_log`.`vw_test`;
CREATE ALGORITHM=UNDEFINED DEFINER=`root`@`localhost` SQL SECURITY DEFINER VIEW `vw_test` AS select sql_no_cache cast(`logaccess`.`horodate` as date) AS `date`,`students`.`idbadge` AS `idbadge`,`students`.`idgroups` AS `groupname`,`students`.`lastname` AS `lastname`,`students`.`firstname` AS `firstname`,timediff(max(`logaccess`.`horodate`),min(`logaccess`.`horodate`)) AS `physical`  from `students`,`logaccess` WHERE `logaccess`.`idbadge`=`students`.`idbadge` GROUP BY cast(`logaccess`.`horodate` as date),`students`.`idbadge`
UNION
select  NULL AS `date` ,`students`.`idbadge` AS `idbadge`,`students`.`idgroups` AS `groupname`,`students`.`lastname` AS `lastname` ,`students`.`firstname` AS `firstname`, timediff(max(`logaccess`.`horodate`),min(`logaccess`.`horodate`)) AS `physical` from `students`,`logaccess` WHERE `idbadge` NOT IN (SELECT `idbadge` from `logaccess`) GROUP BY cast(`logaccess`.`horodate` as date),`students`.`idbadge`

Par contre que je teste le résultat voila l’erreur que j’ai :

Car je ne peux prendre le temps min et max de date car il est NULL …je pense que c’est ca l’erreur ?

Je pense que le problème vient du fait que tu as deux fois la table logaccess, dans le select principal et dans le sous-select, donc dans la sous-requête il ne sait pas dans quelle table prendre “idbadge”. Ca se corrige en définissant un alias aux tables, l1 pour la première et l2 pour la deuxième, et en faisant un select l2.idbadge.
Mais de toute façon, tu n’as pas besoin de ça puisque, comme tu le dis, il n’y a pas de min et max dans ce cas. Il faut donc mettre NULL pour la colonne “physical” pour les étudiants qui n’ont rien dans logacess.
Du coup, le GROUP BY ne sert à rien puisque tu n’as pas besoin de faire de jointure avec logaccess. Chaque groupe aurait une seule ligne.

Sinon, tu vas avoir un gros problème, tu ne peux pas, dans la même vue, afficher chaque logaccess.horodate en même temps que timediff(max(logaccess.horodate),min(logaccess.horodate)). Il te faudrait deux vues différentes pour ça. Une vue pour afficher chaque horodate, l’autre pour afficher le timediff.

Merci…j’ai ca et ca tourne…

DROP VIEW IF EXISTS `badge_log`.`vw_test3`;
CREATE ALGORITHM=UNDEFINED DEFINER=`root`@`localhost` SQL SECURITY DEFINER VIEW `vw_test3` AS select sql_no_cache cast(`logaccess`.`horodate` as date) AS `date`,`students`.`idbadge` AS `idbadge`,`students`.`idgroups` AS `groupname`,`students`.`lastname` AS `lastname`,`students`.`firstname` AS `firstname`,timediff(max(`logaccess`.`horodate`),min(`logaccess`.`horodate`)) AS `physical`,`badge_log`.`fct_presence`(`logaccess`.`idbadge`,cast(`logaccess`.`horodate` as date)) AS `presence` ,`badge_log`.`fct_timetable`(`logaccess`.`idbadge`,cast(`logaccess`.`horodate` as date)) AS `timetable` from `students`,`logaccess` WHERE `logaccess`.`idbadge`=`students`.`idbadge` group by cast(`logaccess`.`horodate` as date),`logaccess`.`idbadge`
UNION
select  NULL AS `date` ,`students`.`idbadge` AS `idbadge`,`students`.`idgroups` AS `groupname`,`students`.`lastname` AS `lastname` ,`students`.`firstname` AS `firstname`, NULL AS `physical` ,NULL AS `presence` ,NULL AS `timetable` from `students` WHERE `idbadge` NOT IN (SELECT `idbadge` from `logaccess`)

Mais par contre je viens de me rendre compte que cela ne corresponds pas tout à fait a ceux que je veux faire…

Donc la je galère…encore plus… j’ai pas les bases nécéssaires…mais bon le métier commence a rentrer comme on dit :pt1cable:

Ben oui, tu fais un GROUP BY avec logaccess.horodate, donc automatiquement, le timediff(max(logaccess.horodate),min(logaccess.horodate)) renverra toujours 0. Et le problème, c’est que si tu ne mets pas logaccess.horodate dans le GROUP BY, tu ne pourras pas le mettre non plus dans le SELECT.
C’est pour ça que les deux sont incompatibles :confused: Il faut choisir : soit tu affiches le timediff, soit tu affiches chaque horodate, tu ne peux pas faire les deux dans la même vue.