utiliser CONCAT/DISTINCT ?

utiliser CONCAT/DISTINCT ? - SQL/NoSQL - Programmation

Marsh Posté le 10-01-2013 à 13:34:22    

Bonjours a tous !
 
Alors je vous explique la situation, j'ai une base de donnée de ce type
 
Matricule  |  Nom  | Prenom  | Commentaire                Ligne
---------------------------------------
0111 | Nom1  | Prenom1  | commentaire1                    1
0111 | Nom1  | Prenom1  |                                        2
0111 | Nom1  | Prenom1  | com                                 3
0111 | Nom2  | Prenom2  | commentaire2                    4
0222 | Nom2  | Prenom3  | commentaire2                    5
0333 | Nom3  | Prenom3  | commentaire3                    6
 
et je  voudrais d'afficher uniquement les lignes 1,4,5,6.( les lignes ne sont pas dans la base de donnée bien entendu)
 
Je pensais alors a concatener le nom et prenom et apres faire un distinct dessus est ce possible ?
 
SELECT DISTINCT( Concat(Nom,Prenom)), Matricule, Commentaire FROM Matable;
 
Thornac

Reply

Marsh Posté le 10-01-2013 à 13:34:22   

Reply

Marsh Posté le 10-01-2013 à 16:39:42    

Le distinct n'est pas une fonction et il s'applique sur l'ensemble des colonnes sélectionnées, donc dans ton cas, du moment que tu affiches le commentaire, il te retournera les lignes 2 et 3.
 
Là comme ça je ne vois pas trop de solution, mais la structure de table est un peu bizarre. Ne vaudrait-il pas mieux sortir le champ commentaire dans une table séparée, liée à la première par le numéro de matricule? Comme ça dans ta première table tu n'a pas de doublon, et ça paraîtrait plus naturel.


---------------
Origin / PSN / Steam / Uplay : x1fr - bnet : Fab#2717
Reply

Marsh Posté le 10-01-2013 à 22:35:58    

GROUP BY nom,prenom
 
ou
 
GROUP BY CONCAT (nom,prenom)
 
Je te donne les deux, car selon le cas, l'une est plus rapide que l'autre et vice versa.


---------------
Directeur Technique (CTO)
Reply

Marsh Posté le 10-01-2013 à 23:08:13    

Tu ne pourras pas faire de select sur un champ qui n'est pas dnas le group by (autre que sum, count, etc...)


---------------
Origin / PSN / Steam / Uplay : x1fr - bnet : Fab#2717
Reply

Marsh Posté le 11-01-2013 à 09:55:40    

Je vous remercie de vos réponse, j'ai essayé de mettre un group by nom,prenom ca n'affiche plus aucun doublons certes mais j'ai plus aucune autre information que les noms et les prénoms !

Reply

Marsh Posté le 11-01-2013 à 10:15:46    

Normal (cf mon poste au dessus)
 
Et si tu rajoutes le champ commentaires dans le select, tu sera obligé de l'ajouter aussi dans le group by, et du coup ça ne réglera pas le problème de doublons
 
edit : en même temps, comment tu veux gérer l'affichage des commentaires? si un ensemble nom/prénom a 3 commentaires, tu ne veux afficher que le premier? une concaténation des 3?


Message édité par x1fr le 11-01-2013 à 10:17:36

---------------
Origin / PSN / Steam / Uplay : x1fr - bnet : Fab#2717
Reply

Marsh Posté le 11-01-2013 à 10:23:25    

A priori, le commentaire le plus long ...
 
Utiliser les clause HAVING et MAX, prévues pour fonctionner avec le GROUP BY ?
 
N'ayant plus la syntaxe exacte en tête, je me contente de vous souffler l'idée :)


Message édité par Farian le 11-01-2013 à 10:26:06
Reply

Marsh Posté le 11-01-2013 à 11:39:49    

Il est nécessaire que j'affiche que le commentaire correspondant a la première fois ou le nom et prénom apparaisse dans la table. si la ligne trois serais lu en premier dans la base de donnée alors il faudrait qu'il n'affiche uniquement "com". Mais je ne suis même pas sure que ce soit possible uniquement en SQL >.>
 
Je ne sais pas qui a conçu cette base de donnée mais je l'étriperais bien ahah ^^

Reply

Marsh Posté le 11-01-2013 à 12:39:49    

La seule manière de récupérer des données distinctes serait un
 

Code :
  1. SELECT
  2.    MIN(matricule),
  3.    Nom,
  4.    Prenom,
  5.    MIN(commentaire)
  6. FROM <taTable>
  7. GROUP BY
  8.   Nom,
  9.   Prenom


 
Maintenant, le MIN(commentaire) ne te donnera évidemment pas la première ligne dans la base, c'est un choix d'une fonction d'aggrégation qui est arbitraire, tu pourrais en prendre une autre, mais le problème de l'arbitraire resterait.
Le MIN(matricule) est aussi arbitraire, mais si on a toujours le même matricule pour un couple "Nom/prénom", pas de problème.
La notion de "première ligne dans la base" ne fait d'ailleurs pas de sens.
Si tu n'as pas d'autre colonne dans ta table (id autoincrémenté, datetime), tu ne peux rien faire...


Message édité par deliriumtremens le 11-01-2013 à 12:41:49
Reply

Marsh Posté le 11-01-2013 à 13:21:39    

Donc comme l'as dit x1fr le group by ne peut pas être utiliser si je veux afficher les autres donnée que le nom et prenom, ensuite je ne suis pas sure de comprendre ce que tu veux faire avec min ?  
 
Quand tu parle d'une colonne date time c'est a dire une colonne qui référence l'heure pour de l'insertion de ces champs ? Si oui, je vais vérifier c'est bien possible car la table est juste immense !

Reply

Marsh Posté le 11-01-2013 à 13:21:39   

Reply

Marsh Posté le 11-01-2013 à 13:44:03    

En fait, pour faire une requête correcte avec un group by, tous les champs qui ne sont pas dans une fonction d'aggrégation (MIN, MAX, SUM, COUNT, etc.) doivent être présents dans le GROUP BY.
 
Donc, pour avoir des résultats groupés par nom et prénom, il faut que tous les autres champs soient dans des fonctions d'aggrégation (bon pour le matricule,en fait, on pourrait aussi l'utiliser dans le GROUP BY).
 
C'est pour ça que j'utilise un MIN sur commentaire.
 
Maintenant, s'il y a une clé primaire autoincrémentée, ou un champ de type timestamp ou datetime (qui, comme tu le dits, référence la date et l'heure lors de l'insertion), il y aurait moyen de faire plus propre.

Reply

Marsh Posté le 11-01-2013 à 14:04:08    

D'accord merci de tes explication, Mais ils se trouve que je doit aussi afficher des dates et plein d'autre type que des chaines cela fonctionnerais t-il ? (Je t'avoue ne jamais avoir fait attention a ces fonctions min et max dans les docs étant donné que je n'ais jamais été amené à les utiliser.  
 
Je viens à l'instant de constater qu'il y à bien un timestamp. Je pense comprendre de qu'elle moyens tu parle mais je ne vois pas trop comment différencier les doublons, par l’horaire qui serais plus récent mais comment les comparer uniquement entre eux ?  
 
Encore merci de vos réponse et de votre rapidité à me répondre !

Reply

Marsh Posté le 11-01-2013 à 15:09:08    

Les fonctions d'aggrégations marchent sur à peu près tous les types de champs, oui.
 
Sinon, admettons que tu as un champ timestamp (ou un type date quelconque, le plus précis étant le mieux) nommé insertDate (original, non ?)
 
Alors, ta requête deviendrait (jointure sur une requête sur la même table avec une recherche de la plus petite "date d'insertion" )
 

Code :
  1. SELECT t.nom, t.prenom, t.matricule, t.commentaire from maTable t
  2. INNER JOIN
  3.      (SELECT t1.nom, t1.prenom, min(t1.insertDate) as minTime
  4.       FROM maTable t1
  5.       GROUP BY t1.nom, t1.prenom) as minQuery
  6.   ON t.nom = minQuery.nom AND t.prenom = minQuery.prenom AND t.insertDate = minQuery.minTime


 
Tu peux regarder le résultat ici, j'ai rajouté des "dates d'insertion" à la noeud.
 
L'avantage, c'est que tu n'as plus rien d'arbitraire, et que tu n'as plus à te soucier de fonctions d'aggrégations dans la requête principale.
 
Le seul risque, c'est d'avoir 2 lignes dans ta table avec les mêmes noms et prénoms et la même "insertDate". Mais le risque me paraît faible (?)
Pour vérifier ce point :
 

Code :
  1. SELECT nom, prenom
  2. FROM maTable
  3. GROUP BY nom, prenom, insertDate
  4. HAVING COUNT(*) > 1


 
Si la requête ne renvoie rien, c'est gagné !


Message édité par deliriumtremens le 11-01-2013 à 15:13:18
Reply

Marsh Posté le 11-01-2013 à 16:55:19    

Parfaitement ce que je voulais ! Encore merci ! Pas encore exactement tout compris à l'opération (compris ce qu'elle fait mais pas comment elle le fait ) mais je compte bien étudiez cela plus en détail !

Reply

Marsh Posté le 14-01-2013 à 16:18:18    

Me revoilà !  
 
J'étais entrain d'étudier le code que tu ma montrer et je me posais une question  
 
Si, je travail sur  même table, je vais avoir besoin de cette jointure dès que je veux enlever des doublons même si je ne cherches pas a avoir leurs nom mais plutot leurs dates d'embauche ou de sortie de l'entreprise?  
 
Thornac


Message édité par Thornac le 14-01-2013 à 16:31:24
Reply

Marsh Posté le 15-01-2013 à 10:32:32    

Lapin compris (ou en tout cas pas sûr). A priori je dirais oui.
 
Tu as des dates d'embauche ou de sortie dans la même table, et tu voudrais savoir si cette requête est utilisable pour ça ?
 
Mais as-tu un champ "DateEmbauche" et un champ "DateSortie", répétés à chaque entrée ?
Structure étrange...
 
Essaie de préciser un peu le besoin (et puis c'est difficile de répondre sans connaître la structure complète de la table)

Reply

Marsh Posté le 15-01-2013 à 11:39:15    

Désoler, disons qu'il ont regrouper dans une même tables a peut prêt tout a ce qu'on dirais, donc sur la table énoncer au début j'ai date embauche et date sortie qui sont dans la même table.
 
 Il se trouve que je doit compter le nombre de sortie ainsi le nombre
d'embauche par mois et par année mais comme j'ai des doublons il est nécessaire que je les enlève de la même façon non ?
 
 Saurais tu notamment si je peut découper avec substr() des dates afin de les regrouper par moi et année ? Je n'ai pas accès aux fonction Year(), Month(), et Day() sur le logiciel qui m'est imposer d'utiliser par mon entreprise ...
 
edit :
 
J'ai rajouté http://sqlfiddle.com/#!2/f5598/1 ce qu'il manquait c'est a dire les dates embauche et sortie avec les requêtes qui me permette de trouver combien d'employer ont quitter ou ont été embaucher par mois. Sauf que bien évidement il faut que ce soit en une requête et qu'il ne prenne pas des dates des doublons en compte ... Donc faut il que j'insère dans ma requête nom et prénom ... Logiquement oui il me semble et bien avec les noms et préno car il peut y avoir deux sortie ou deux embauche le même jours.


Message édité par Thornac le 15-01-2013 à 14:51:15
Reply

Marsh Posté le 15-01-2013 à 17:29:24    

Il y a effectivement des fonctions sur les chaînes de caractères dans différents SGBD (Système de gestion de base de données), maintenant ils sont différents de l'un à l'autre.
 
Si tu n'as pas les fonctions Year, Month et Day, tu pourrais me dire quelle SGBD vous utilisez ? Ca aura un impact sur les fonctions utilisées...
Ensuite, tu es sûr que les dates d'embauche et de sortie sont bien des colonnes de type "Date", parce qu'il est possible qu'ils aient été stockés dans un format type Varchar, voire entier, ça se voit plus souvent qu'on pense, même si c'est une bien mauvaise idée. (bref, si tu as le nom précis du type de ces colonnes, ça aidera sûrement).
 
 
EDITH:
Ce qui est bizarre dans ton exemple, c'est qu'il y a des dates d'entrée et de sortie différentes pour le même couple Nom/Prénom. C'est voulu ? Ca correspond à la réalité ?


Message édité par deliriumtremens le 15-01-2013 à 17:33:50
Reply

Marsh Posté le 16-01-2013 à 10:44:49    

Donc pour te répondre c'est une base de donnée HyperFileSQL de ce que j'en ais compris. Il semblerait que les fonctions utilisable soit celle ci : http://doc.pcsoft.fr/fr-fr/?203400 [...] equete-sql .
J'avoue ne pas pouvoir confirmer si c'est un format date ou une chaine de caractère. Je n'ai encore jamais utiliser ce genre de base de donné lors de ma formation.
 
Donc pour ce qui est des dates. J'ai écrit des dates plus ou moins au hasard sur le site SQLfiddle. Mais dans mon cas je peut avoir des employer qui comporte forcement un date d'embauche mais pas forcement une date de sortie. Et cette dernière serais forcement après la date d'embauche bien évidement.
 

Code :
  1. SELECT
  2. COUNT(SUBSTR(t1.IT_DATEMB,3,4)) AS nbEmbauche
  3. FROM
  4. maTable t1
  5. WHERE
  6. SUBSTR(t1.IT_DATEMB,1,4) = '2012'
  7. GROUP BY SUBSTR(t1.IT_DATEMB,3,4);


Voilà le fruit de mes recherches. Avec ce code j’obtiens le compte du nombre d'embauche, pour l'année 2012 le tout triée par mois. ( Si, il y au moins une embauche par mois, ce qui est apparemment le cas de mon entreprise). Je peut notamment récupérer de la même façon les sorties. Mais je n'arrive pas a unir les deux car lorsque quand je join les deux j'obtiens un problème liée à la condition qui devient.
 

Code :
  1. WHERE
  2. SUBSTR(t1.IT_DATEMB,1,4) = '2012' OR SUBSTR(t1.IT_DATSOR,1,4) = '2012'


 
Il se trouve que avec cette condition me récupère toutes les dates que j'ai besoin. Mais le problème est que j'obtiens par les count(), un résultat équivalent pour les deux count(). Je suppose donc que il ne compte pas séparément les dates embauches et sorties. Ce qui m'a amené à tester une nouvelle requête avec des INNER JOIN mais sans résultat probant.

Reply

Marsh Posté le 16-01-2013 à 11:30:40    

Pas mal de manières de résoudre, une des solutions serait de faire une sous-requête avec une UNION.
 
 

Code :
  1. SELECT SUM(nbEmbauches), SUM(nbSorties), month
  2. FROM
  3. (SELECT
  4.     SUBSTR(t1.IT_DATEMB, 3, 4) as month,
  5.     COUNT(*) AS nbEmbauches,
  6.     0 AS nbSorties
  7.   FROM maTable t1
  8.   WHERE SUBSTR(t1.IT_DATEMB,1,4) = '2012'
  9.   GROUP BY SUBSTR(t1.IT_DATEMB,3,4)
  10.   UNION
  11.   SELECT
  12.     SUBSTR(t1.IT_DATSOR, 3, 4) as month,
  13.     0 AS nbEmbauches,
  14.     COUNT(*) AS nbSorties
  15.   FROM maTable t1
  16.   WHERE SUBSTR(t1.IT_DATESOR,1,4) = '2012'
  17.   GROUP BY SUBSTR(t1.IT_DATESOR,3,4)
  18.   )
  19. GROUP BY month;


Message édité par deliriumtremens le 16-01-2013 à 11:31:04
Reply

Marsh Posté le 17-01-2013 à 18:18:12    

Bon bah rien à dire ça me donne exactement ce qu'il me fallait ... le pire c'est que j'avais essayer l'union aussi avant ta solution mais j'avais des erreurs à cause des 0 AS Sortie et 0 AS Embauche. que je n'avais pas mis donc j'avais quand même des erreurs ... Donc bah j'ai adapté ton code avec l’enlèvement de doublons et certains trucs en plus qu'il mettais demander et cela marche parfaitement.
 
 En tout cas je te remercie grandement de ton aide. J'ai appris beaucoup !

Reply

Marsh Posté le    

Reply

Sujets relatifs:

Leave a Replay

Make sure you enter the(*)required information where indicate.HTML code is not allowed