MySQL : forcer la position d'un résultat ?

MySQL : forcer la position d'un résultat ? - SQL/NoSQL - Programmation

Marsh Posté le 06-05-2021 à 11:02:41    

Hello !
 
Je voudrais savoir s'il est possible de forcer la position d'un résultat au sein d'une requête SQL.
 
Explication :
 
SELECT position, nom FROM produits ORDER BY position
 
donnerait:
 
Position,Nom
1,"Clio"
2,"Golf
3,"A3"
4,"Leon"
 
Et moi je voudrais forcer "A3" pour qu'il arrive en 2e, sans changer le reste.
Ainsi j'aurais en résultat :
1,"Clio"
3,"A3"
2,"Golf
4,"Leon"
 
La base fait plusieurs milliers de ligne.
 
Là ce sont des données d'exemple. Le vrai cas d'usage c'est de trier des produits par Chiffre d'affaire descendant mais pouvoir forcer, en position 3 par exemple, un produit même si son CA est faible
 
Merci !


---------------
Bha ouais mais bon, m'enfin quoi...
Reply

Marsh Posté le 06-05-2021 à 11:02:41   

Reply

Marsh Posté le 06-05-2021 à 13:05:17    

Oui, tu peux faire un truc comme ça :
SELECT IIF(position='A3',-1,position) as position, nom
FROM produits
ORDER BY position

Reply

Marsh Posté le 06-05-2021 à 16:20:05    

Merci !

 

Et si je veux pouvoir en forcer 2 par exemple ?
Là ce que tu as fait c'est de remonter d'une place le "A3"?
Moi je voudrais forcer "A3" en position 2, quelle que soit sa position initiale
Et pouvoir le faire sur plusieurs entrées

 

Merci beaucoup ;)

Message cité 1 fois
Message édité par vanquishV12 le 06-05-2021 à 16:31:09

---------------
Bha ouais mais bon, m'enfin quoi...
Reply

Marsh Posté le 06-05-2021 à 16:40:34    

Si tu as une sélection plus complexe tu devrais plutôt utiliser case :
https://dev.mysql.com/doc/refman/5.7/en/case.html
 
Exemple :

Code :
  1. SELECT
  2.     CASE nom
  3.         WHEN 'A3' THEN 1.9
  4.         WHEN 'Golf' THEN 2.9
  5.         ELSE position
  6.     END CASE
  7.     AS position,
  8.     nom
  9. FROM produits ORDER BY position


Par contre ne forçant des positions tu risque d'avoir des conflits avec des égalités de position (c'est pourquoi au lieu de mettre 2 et 3 j'ai mis 1.9 et 2.9, de cette manière il seront bien avant l'éventuel équivalent).


---------------
D3
Reply

Marsh Posté le 06-05-2021 à 16:59:14    

Super cool merci


---------------
Bha ouais mais bon, m'enfin quoi...
Reply

Marsh Posté le 06-05-2021 à 16:59:49    

vanquishV12 a écrit :

Merci !
 
Et si je veux pouvoir en forcer 2 par exemple ?
Là ce que tu as fait c'est de remonter d'une place le "A3"?  
Moi je voudrais forcer "A3" en position 2, quelle que soit sa position initiale
Et pouvoir le faire sur plusieurs entrées
 
Merci beaucoup ;)


Non, ce que je fais c'est forcer la première position à A3 (position "-1" ) qui sera toujours avant n'importe quelle autre position.  

Reply

Marsh Posté le 06-05-2021 à 17:08:05    

Je ne connaissais pas IIF(), du coups j'ai pensé que c'était un position-1 implicite.
 
Il faudrait ptet que tu gères un vrai compteur car à l'heure actuel tu es complétement sûr de ta colonne position (incrément partant de 1 et sans trou) ?


---------------
D3
Reply

Marsh Posté le 06-05-2021 à 18:26:42    

Alors non, en fait, ce n'est même pas sur position que je dois trier, en y réfléchissant, mais sur "CA" (chiffre d'affaire) et là bha, ça va de 0 à plusieurs centaines de milliers, parfois avec des virgules

 

PS : super pour IIF, je pensais que c'était une faute de frappe au départ


Message édité par vanquishV12 le 06-05-2021 à 18:33:10

---------------
Bha ouais mais bon, m'enfin quoi...
Reply

Marsh Posté le 06-05-2021 à 19:58:29    

mechkurt a écrit :

Je ne connaissais pas IIF(), du coups j'ai pensé que c'était un position-1 implicite.
 
Il faudrait ptet que tu gères un vrai compteur car à l'heure actuel tu es complétement sûr de ta colonne position (incrément partant de 1 et sans trou) ?


En fait je crois que c'est assez spécifique à SQL Server mais Grosso modo c'est comme un case...  
 

Reply

Marsh Posté le 07-05-2021 à 11:22:50    

Du coup le fait que mes "numéros" ne se suivent pas change la méthode à utiliser ?


---------------
Bha ouais mais bon, m'enfin quoi...
Reply

Marsh Posté le 07-05-2021 à 11:22:50   

Reply

Marsh Posté le 07-05-2021 à 16:35:34    

Ça vas être nettement plus compliquer d'intercaler des valeurs fixe de position si tu ne connait pas les valeurs de tri de la colonne renvoyé à l'avance (mettre avant ou après serait simple mais là non).
Faut que tu gères une variable (et donc une procédure), avec peut être en plus une sous requête...
 
...c'est loin d'être anodin, ce serait ptet plus simple (si tu le peux) de faire ce traitement dans ton langage de programmation favoris  ^^


---------------
D3
Reply

Marsh Posté le 07-05-2021 à 20:35:32    

Au final... c'est quoi l'intérêt ?

Reply

Marsh Posté le 08-05-2021 à 14:47:30    

Trier par CA DESC mais forcer la mise en avant de 4 ou 5 produits en haut de listing, quel que soit leur CA


---------------
Bha ouais mais bon, m'enfin quoi...
Reply

Marsh Posté le 08-05-2021 à 14:48:50    

mechkurt a écrit :

Ça vas être nettement plus compliquer d'intercaler des valeurs fixe de position si tu ne connait pas les valeurs de tri de la colonne renvoyé à l'avance (mettre avant ou après serait simple mais là non).
Faut que tu gères une variable (et donc une procédure), avec peut être en plus une sous requête...
 
...c'est loin d'être anodin, ce serait ptet plus simple (si tu le peux) de faire ce traitement dans ton langage de programmation favoris  ^^


En fait j’ai mal répondu
Je trie par ÇA mais j’ai bien une autre colonne avec des id


---------------
Bha ouais mais bon, m'enfin quoi...
Reply

Marsh Posté le 08-05-2021 à 17:31:49    

vanquishV12 a écrit :

Trier par CA DESC mais forcer la mise en avant de 4 ou 5 produits en haut de listing, quel que soit leur CA


Dans ce cas, pourquoi ne pas faire une requête avec tes 4 ou 5 produits et un UNION avec une autre requête avec ton tri en excluant les 4/5 produits précédents.  

Reply

Marsh Posté le 08-05-2021 à 23:05:38    

Justement les 4 ou 5 produits ne sont pas forcément les premiers
 
Ils peuvent être positionnés la ou on veut  
Et ça peut être 0, 1 , 2, 10 produits dont on force la position
 
Je sais pas si c’est clair ?


---------------
Bha ouais mais bon, m'enfin quoi...
Reply

Marsh Posté le 09-05-2021 à 00:04:45    

Si mais franchement, le mieux est de gérer ça côté programmation je pense.

Reply

Marsh Posté le 09-05-2021 à 22:48:18    

antac a écrit :

Si mais franchement, le mieux est de gérer ça côté programmation je pense.


+1


---------------
D3
Reply

Marsh Posté le 09-05-2021 à 23:21:36    

tu ajoutes une colonne favorite ( 0, 1)
 
et tu fais order by favorite desc, position


---------------

Reply

Marsh Posté le 09-05-2021 à 23:41:02    

Sauf que là les favorites seront avant, lui il veut les intercaler a des places "fixe" genre 2ème ou 4ème sans savoir avant les valeurs retourné par son ORDER BY...


---------------
D3
Reply

Marsh Posté le 10-05-2021 à 00:35:29    

Salut,
 

Citation :

Et ça peut être 0, 1 , 2, 10 produits dont on force la position


Elles ne sont pas identifiées et déterminées autrement que par leurs noms ? De façon à pouvoir le réaliser directement via ORDER ?
 
En l'état, je ne vois que ce genre de démarche :
 

Code :
  1. $count = SELECT COUNT(*) FROM produits /*WHERE nom <> 'A3'*/;
  2.  
  3. SELECT * FROM produits WHERE nom <> 'A3' LIMIT 0, 1 ORDER BY nom
  4. UNION
  5. SELECT * FROM produits WHERE nom = 'A3'
  6. UNION
  7. SELECT * FROM produits WHERE nom <> 'A3' LIMIT 1, $count - 2 ORDER BY nom


 
Avec plusieurs produits à positions forcées, je laisse imaginer la complexité (avec la propriété d'UNION on pourrait éventuellement supprimer les clauses WHERE et LIMIT de la dernière)
 

Citation :

tu ajoutes une colonne favorite ( 0, 1)


 
Une colonne avec cette position forcée (sinon NULL) et la comparer au ROW_NUMBER ?
 

Code :
  1. SELECT *
  2. FROM(
  3.    SELECT ROW_NUMBER() rn, p.*
  4.    FROM produits p
  5. ) t
  6. ORDER BY NULLIF(position_forcee, rn), position_forcee IS NULL


Message édité par pluj le 10-05-2021 à 00:57:41
Reply

Marsh Posté le 10-05-2021 à 08:32:37    

vanquishV12 a écrit :

Trier par CA DESC mais forcer la mise en avant de 4 ou 5 produits en haut de listing, quel que soit leur CA


Ah ben tiens, j'ai fait ça y'a pas longtemps pour un forum : trier les sujets par la date de dernier message posté mais avec certains sujets qui ont un rang de 1 à n que je veux mettre en top de ma liste de sujet.
 
J'ai fait une requête SQL avec un UNION : dans la première partie de la requête, les sujets ayant un rang et dans la seconde parte, les sujets n'en ayant pas.
Edit : voici le genre de requête que ça donne :

Citation :


SELECT rkt.ForumTopicID, rkt.ForumTopicTitle, rkt.ForumTopicRank, rkt.ForumMessageID, rkt.LastTopicForumMessageDate,  
@rownum := @rownum + 1 AS TopicPos  
FROM  
     (SELECT ft.ForumTopicID, ft.ForumTopicTitle, ft.ForumTopicRank, fm.ForumMessageID, fm.ForumMessageDate AS LastTopicForumMessageDate
      FROM ForumTopics ft, ForumMessages fm,  
             (select @rownum := 0) AS r,  
             (SELECT tfm.ForumTopicID, MAX(tfm.ForumMessageID) AS LastTopicMessageID  
             FROM ForumMessages tfm GROUP BY tfm.ForumTopicID) AS LastMsgs  
      WHERE ft.ForumTopicID = fm.ForumTopicID AND ft.ForumTopicID = LastMsgs.ForumTopicID  
                        AND LastMsgs.LastTopicMessageID = fm.ForumMessageID AND ft.ForumTopicRank IS NOT NULL  
      ORDER BY ft.ForumTopicRank) AS rkt  
UNION  
SELECT rkt.ForumTopicID, rkt.ForumTopicTitle, rkt.ForumTopicRank, rkt.ForumMessageID, rkt.LastTopicForumMessageDate,  
@rownum := @rownum + 1 AS TopicPos  
FROM  
     (SELECT ft.ForumTopicID, ft.ForumTopicTitle, ft.ForumTopicRank, fm.ForumMessageID, fm.ForumMessageDate AS LastTopicForumMessageDate
      FROM ForumTopics ft, ForumMessages fm,
               (select @rownum := 0) AS r,  
               (SELECT tfm.ForumTopicID, MAX(tfm.ForumMessageID) AS LastTopicMessageID  
                FROM ForumMessages tfm GROUP BY tfm.ForumTopicID) AS LastMsgs  
      WHERE ft.ForumTopicID = fm.ForumTopicID AND ft.ForumTopicID = LastMsgs.ForumTopicID  
                 AND LastMsgs.LastTopicMessageID = fm.ForumMessageID AND ft.ForumTopicRank IS NULL  
      ORDER BY LastTopicForumMessageDate DESC) AS rkt  
GROUP BY rkt.ForumTopicID ORDER BY TopicPos


Le truc intéressant, c'est le (select @rownum := 0) AS r dans le FROM et le @rownum := @rownum + 1 AS TopicPos dans le SELECT.


Message édité par rufo le 10-05-2021 à 10:09:48

---------------
Astres, outil de help-desk GPL : http://sourceforge.net/projects/astres, ICARE, gestion de conf : http://sourceforge.net/projects/icare, Outil Planeta Calandreta : https://framalibre.org/content/planeta-calandreta
Reply

Marsh Posté le 10-05-2021 à 10:05:11    

Pfouuaa la requête ^^
 
Merci
 
Je vois que c'est compliqué. Merci pour toutes ces réponses
La raison pour laquelle je veux faire ça en SQL c'est que pour l'usage que j'en ai, on veut absolument éviter de toucher au code et tout faire en SQL, pour plein de raisons surtout internes/liées au contexte


---------------
Bha ouais mais bon, m'enfin quoi...
Reply

Marsh Posté le 10-05-2021 à 10:10:48    

Je viens de la simplifier en virant les champs qui servent à rien pour ton pb. ;)
 
Edit : tu remarqueras que le contenu du 1er SELCT au niveau du UNION est identique tout comme les 2 FROM. Ce qui change, c'est dans le WHERE avec dans la première partie (avant le UNION, tu as "AND ft.ForumTopicRank IS NOT NULL" et dans l'autre, tu as ft.ForumTopicRank IS NULL. Il ya aussi le ORDER BY : dans le premier, tu as ORDER BY ft.ForumTopicRank alors que dans la 2ème partie du UNION, tu as ORDER BY LastTopicForumMessageDate DESC
En gros, si je résume la requête :
SELECT mes topics, position calculée
FROM mes tables
WHERE mes critères AND Topics avec un rang
ORDER BY rang ASC
UNION
SELECT mes topics, position calculée
FROM mes tables
WHERE mes critères AND Topics sans rang
ORDER BY date de dernier message posté DESC
le tout ORDER BY position calculée
 
La, position calculée l'est grâce à cette table temporaire (select @rownum := 0) AS r qui initialise ma variable @rownum à 0 et dans le select, chaque enregistrement affichée incrémente de 1 ma variable @rownum. Comme les topics avec un rang sont dans la partie avant le UNION, ils sortent en premier car ils auront la valeur de leur variable @rownum plus faible que pour les topics qui sortent via la 2ème partie du UNION.


Message édité par rufo le 10-05-2021 à 10:18:20

---------------
Astres, outil de help-desk GPL : http://sourceforge.net/projects/astres, ICARE, gestion de conf : http://sourceforge.net/projects/icare, Outil Planeta Calandreta : https://framalibre.org/content/planeta-calandreta
Reply

Marsh Posté le 10-05-2021 à 11:20:50    

Un grand merci !


---------------
Bha ouais mais bon, m'enfin quoi...
Reply

Marsh Posté le    

Reply

Sujets relatifs:

Leave a Replay

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