J'ai une table par exemple des étudiants:
id | name ---|------ 1 | A 2 | B 3 | C 4 | D 8 | H 7 | G 6 | F 5 | E
Comment écrire un sql dans mysql pour que les 4 premiers étudiants soient triés par id croissant et ordre de repos par id décroissant La sortie devrait être quelque chose comme ça
id | name -- |----- 1 | A 2 | B 3 | C 4 | D 5 | E 6 | F 7 | G 8 | H`
3 Réponses :
Vous utilisez une version de MySQL antérieure à 8+, ce qui signifie que vous ne pouvez pas utiliser de fonctions analytiques ici. Voici une façon de faire cela, en utilisant une sous-requête corrélée avec une expression CASE
:
SELECT t1.id, t1.name FROM yourTable t1 ORDER BY CASE WHEN ROW_NUMBER() OVER (ORDER BY id) <= 4 THEN 0 ELSE 1 END, CASE WHEN ROW_NUMBER() OVER (ORDER BY id) <= 4 THEN id ELSE -id END;
La raison pour laquelle je calcule le numéro de ligne ci-dessus avec une sous-requête corrélée, plutôt que d'utiliser simplement l ' id
, est que peut-être que vos valeurs id
ne commencent pas toujours à 1
, voire être contigus. Le numéro de ligne peut toujours cibler correctement les enregistrements de première ligne, comme triés par id
, tandis que la valeur de id
elle-même peut ne pas toujours suffire. p>
Notez que les fonctions analytiques rendent le code beaucoup plus facile à lire ici. Voici ce que vous pouvez faire avec MySQL 8+:
SELECT t1.id, t1.name FROM yourTable t1 ORDER BY CASE WHEN (SELECT COUNT(*) FROM yourTable t2 WHERE t2.id <= t1.id) <= 4 THEN 0 ELSE 1 END, CASE WHEN (SELECT COUNT(*) FROM yourTable t2 WHERE t2.id <= t1.id) <= 4 THEN id ELSE -id END;
Je déconseille fortement la première approche. L'utilisation d'une sous-requête corrélée pour énumérer les lignes est très coûteuse. Si vous utilisez MySQL 8+, alors row_number ()
est une très bonne solution.
@GordonLinoff Et je suis d'accord avec vous. Si l'OP a de telles exigences à long terme, la mise à niveau / le passage à une base de données qui prend en charge les fonctions analytiques de base pourrait être en ordre.
Vous pouvez utiliser une sous-requête corrélée pour calculer le "rang" de la ligne. Le tri est simple:
SELECT *, (SELECT COUNT(*) FROM t AS x WHERE id < t.id) AS rn FROM t ORDER BY CASE WHEN rn >= 4 THEN -rn END, rn
SELECT COUNT (*) FROM t AS x WHERE id attribue des numéros consécutifs à chaque ligne à partir de 0
CASE WHEN rn> = 4 THEN -rn END
affecte NULL au rang numéro 0 ... 3 donc un tri secondaire est nécessaire. Sur la base de vos exemples de données, la méthode la plus simple serait:
select s.* from students s cross join (select s2.id from students s2 order by s2.id limit 3, 1 ) as s4 order by (case when s.id <= s4.id then 1 else 2 end), (case when s.id <= s4.id then s.id end), s.name desc;
Si vous ne savez pas où se trouve le quatrième identifiant, alors:
order by (case when id <= 4 then 1 else 2 end), (case when id <= 4 then id end), name desc;
Oui, vous pouvez utiliser l'instruction
case
dans l'ordre par clause