Existe-t-il un bon moyen dans MySQL pour répliquer la fonction SQL Server ROW_NUMBER()
?
Par exemple:
SELECT
col1, col2,
ROW_NUMBER() OVER (PARTITION BY col1, col2 ORDER BY col3 DESC) AS intRow
FROM Table1
Ensuite, je pourrais, par exemple, ajouter une condition à limiter intRow
à 1 pour obtenir une seule ligne avec le plus haut col3
pour chaque (col1, col2)
paire.
greatest-n-per-group
pour vous guider vers des questions similaires.Sql-Server
balise car il s'agissait de l'élément le plus voté dans la recherche de balises combinées, mais pas vraiment pertinent pour SQL Server.Réponses:
C'est un maximum par groupe , l'une des questions SQL les plus fréquemment posées (car il semble que cela devrait être facile, mais en fait ce n'est pas le cas).
Je plump souvent pour une auto-jointure nulle:
"Obtenez les lignes du tableau pour lesquelles aucune autre ligne avec col1, col2 correspondant n'a un col3 supérieur." (Vous remarquerez cela et la plupart des autres solutions maximales par groupe renverront plusieurs lignes si plusieurs lignes ont le même col1, col2, col3. Si c'est un problème, vous devrez peut-être un post-traitement.)
la source
SELECT t1.id FROM test t1 LEFT JOIN test t2 ON t1.id>t2.id WHERE t2.id IS NULL;
Ne nécessite-t-il pas desn*n/2 + n/2
comparaisons IS NULL pour trouver la seule ligne? Y a-t-il des optimisations que je ne vois pas? J'ai essayé de poser la question similaire à Bill dans un autre fil, mais il semble l'avoir ignoré.SELECT t0.col3 FROM table AS t0 WHERE NOT EXISTS (select 1 from table AS t1 ON t0.col1=t1.col1 AND t0.col2=t1.col2 AND t1.col3>t0.col3)
Il n'y a pas de fonctionnalité de classement dans MySQL. Le plus proche que vous pouvez obtenir est d'utiliser une variable:
Oui. S'il s'agissait d'Oracle, vous pourriez utiliser la fonction LEAD pour atteindre un pic à la valeur suivante. Heureusement, Quassnoi couvre la logique de ce que vous devez implémenter dans MySQL .
la source
SELECT @row_num:=@row_num+1 AS row_number, t.id FROM (SELECT * FROM table1 WHERE col = 264 ORDER BY id) t, (SELECT @row_num:=0) var;
Je finis toujours par suivre ce schéma. Compte tenu de ce tableau:
Vous pouvez obtenir ce résultat:
En exécutant cette requête, qui n'a besoin d'aucune variable définie:
J'espère que cela pourra aider!
la source
<
,>
,<=
,>=
poignée CHAR et types de données VARCHAR sur l' ordre alphabétique; Je pense que c'est exactement ce que vous recherchez.row_numbers <= 2
Et merci énormément pour cette réponse Mosty, c'est parfait!la source
Consultez cet article, il montre comment imiter SQL ROW_NUMBER () avec une partition par dans MySQL. J'ai rencontré ce même scénario dans une mise en œuvre de WordPress. J'avais besoin de ROW_NUMBER () et ce n'était pas là.
http://www.explodybits.com/2011/11/mysql-row-number/
L'exemple de l'article utilise une seule partition par champ. Pour partitionner par champs supplémentaires, vous pouvez faire quelque chose comme ceci:
L'utilisation de concat_ws gère les valeurs nulles. J'ai testé cela sur 3 champs en utilisant un int, une date et un varchar. J'espère que cela t'aides. Consultez l'article car il décompose cette requête et l'explique.
la source
limit 18446744073709551615
à laorder by
clause force .concat_ws
avec une chaîne vide''
est dangereuse:concat_ws('',12,3) = concat_ws('',1,23)
. Mieux vaut utiliser un séparateur'_'
ou utiliser la solution @Kenneth Xu.Depuis
MySQL 8.0.0
et au-dessus, vous pouvez utiliser nativement des fonctions fenêtrées.1.4 Quoi de neuf dans MySQL 8.0 :
ROW_NUMBER () over_clause :
Démo:
DBFiddle Demo
la source
Je voterais également pour la solution de Mosty Mostacho avec une modification mineure de son code de requête:
Ce qui donnera le même résultat:
pour la table:
À la seule différence que la requête n'utilise pas JOIN et GROUP BY, en s'appuyant à la place sur select imbriqué.
la source
Je définirais une fonction:
alors je pourrais faire:
Maintenant, vous n'avez pas de sous-requête, que vous ne pouvez pas avoir dans les vues.
la source
requête pour row_number dans mysql
la source
Il n'y a pas de fonction comme
rownum
,row_num()
dans MySQL mais le chemin est comme ci-dessous:la source
La solution que j'ai trouvée la plus efficace consiste à utiliser une sous-requête comme celle-ci:
Les colonnes PARTITION BY sont simplement comparées à '=' et séparées par AND. Les colonnes ORDER BY seraient comparées à «<» ou «>» et séparées par OR.
J'ai trouvé que c'était très flexible, même si c'était un peu cher.
la source
La fonctionnalité de numéro de version ne peut pas être imitée. Vous obtiendrez peut-être les résultats escomptés, mais vous serez très probablement déçu à un moment donné. Voici ce que dit la documentation mysql:
Cordialement, Georgi.
la source
MariaDB 10.2 implémente des "fonctions de fenêtre", y compris RANK (), ROW_NUMBER () et plusieurs autres choses:
https://mariadb.com/kb/en/mariadb/window-functions/
Sur la base d'une conférence à Percona Live ce mois-ci, ils sont raisonnablement bien optimisés.
La syntaxe est identique au code de la question.
la source
Je ne vois pas de réponse simple couvrant la partie "PARTITION PAR" alors voici la mienne:
Dans cet exemple simple, je n'en mets qu'une mais vous pouvez avoir plusieurs parties "PARTITION BY"
la source
Un peu tard mais peut aussi aider quelqu'un qui cherche des réponses ...
Exemple entre les lignes / numéro de ligne - requête récursive qui peut être utilisée dans n'importe quel SQL:
la source
Cela permet d'obtenir les mêmes fonctionnalités que ROW_NUMBER () ET PARTITION BY dans MySQL
la source
Aussi un peu tard mais aujourd'hui j'avais le même besoin donc j'ai fait une recherche sur Google et enfin une approche générale simple trouvée ici dans l'article de Pinal Dave http://blog.sqlauthority.com/2014/03/09/mysql-reset-row -number-for-each-group-partition-by-row-number /
Je voulais me concentrer sur la question initiale de Paul (c'était aussi mon problème), donc je résume ma solution comme un exemple de travail.
Beacuse nous voulons partitionner sur deux colonnes Je créerais une variable SET pendant l'itération pour identifier si un nouveau groupe a été démarré.
Le 3 signifie au premier paramètre de MAKE_SET que je veux les deux valeurs dans le SET (3 = 1 | 2). Bien sûr, si nous n'avons pas deux colonnes ou plus construisant les groupes, nous pouvons éliminer l'opération MAKE_SET. La construction est exactement la même. Cela fonctionne pour moi au besoin. Un grand merci à Pinal Dave pour sa démonstration claire.
la source
ORDER BY
dans une sous-requête, elle peut être ignorée (voir mariadb.com/kb/en/mariadb/… ). La solution suggérée est d'ajouterLIMIT 18446744073709551615
à la sous-requête, ce qui force un tri. Cependant, cela pourrait entraîner des problèmes de performances et n'est pas valable pour les énormes tables vraimentCela pourrait également être une solution:
la source
MySQL prend en charge ROW_NUMBER () depuis la version 8.0+ .
Si vous utilisez MySQL 8.0 ou version ultérieure, vérifiez-la fonction ROW_NUMBER (). Sinon, vous avez émulé la fonction ROW_NUMBER ().
Row_number () est une fonction de classement qui renvoie un numéro séquentiel d'une ligne, à partir de 1 pour la première ligne.
pour une version plus ancienne,
la source
Important: veuillez envisager la mise à niveau vers MySQL 8+ et utiliser la fonction ROW_NUMBER () définie et documentée, et abandonner les anciens hacks liés à une ancienne version limitée de MySQL.
Maintenant, voici un de ces hacks:
Les réponses ici qui utilisent la plupart du temps des variables dans la requête semblent ignorer le fait que la documentation dit (paraphrase):
En tant que tel, il y a un risque qu'ils produisent la mauvaise réponse, car ils font généralement un
Si celles-ci sont évaluées de bas en haut, le numéro de ligne cessera de fonctionner (pas de partitions)
Nous devons donc utiliser quelque chose avec un ordre d'exécution garanti. Entrez CASE WHEN:
Comme le contour ld, l'ordre d'affectation de prevcol est important - prevcol doit être comparé à la valeur de la ligne actuelle avant de lui affecter une valeur à partir de la ligne actuelle (sinon ce serait la valeur col des lignes actuelles, pas la valeur col de la ligne précédente) .
Voici comment cela s'intègre:
Le premier QUAND est évalué. Si le col de cette ligne est le même que le col de la ligne précédente, @r est incrémenté et renvoyé par CASE. Ces valeurs de led de retour sont stockées dans @r. C'est une caractéristique de MySQL que l'affectation renvoie la nouvelle valeur de ce qui est attribué à @r dans les lignes de résultat.
Pour la première ligne du jeu de résultats, @prevcol est null (il est initialisé à null dans la sous-requête), donc ce prédicat est faux. Ce premier prédicat renvoie également false chaque fois que col change (la ligne actuelle est différente de la ligne précédente). Cela entraîne l'évaluation du deuxième QUAND.
Le deuxième prédicat WHEN est toujours faux, et il existe uniquement pour attribuer une nouvelle valeur à @prevcol. Parce que le col de cette ligne est différent du col de la ligne précédente (nous le savons parce que s'il était le même, le premier QUAND aurait été utilisé), nous devons attribuer la nouvelle valeur pour la conserver pour les tests la prochaine fois. Étant donné que l'affectation est effectuée et que le résultat de l'affectation est comparé à null et que tout ce qui est égal à null est faux, ce prédicat est toujours faux. Mais au moins l'évaluer a fait son travail en gardant la valeur de col de cette ligne, donc il peut être évalué par rapport à la valeur de col de la ligne suivante
Parce que le deuxième WHEN est faux, cela signifie que dans les situations où la colonne que nous partitionnons par (col) a changé, c'est ELSE qui donne une nouvelle valeur pour @r, en redémarrant la numérotation à partir de 1
Nous ceci arrivons à une situation où ceci:
A la forme générale:
Notes de bas de page:
Le p dans pcol signifie "partition", le o dans ocol signifie "ordre" - dans la forme générale, j'ai supprimé le "prev" du nom de la variable pour réduire l'encombrement visuel
Les crochets autour
(@pcolX := colX) = null
sont importants. Sans eux, vous affecterez null à @pcolX et les choses cesseront de fonctionnerC'est un compromis que l'ensemble de résultats doit également être ordonné par les colonnes de partition, pour que la comparaison de la colonne précédente fonctionne. Vous ne pouvez donc pas avoir votre numéro de commande ordonné selon une colonne, mais votre jeu de résultats ordonné à une autre. performance
Je n'y ai pas exploré au-delà du test du fonctionnement de la méthode, mais s'il y a un risque que les prédicats du deuxième WHEN soient optimisés (tout ce qui se compare à null est nul / faux alors pourquoi s'embêter à exécuter l'affectation) et non exécuté , il s'arrête également. Cela ne semble pas se produire dans mon expérience, mais je serai heureux d'accepter les commentaires et de proposer une solution si cela pouvait raisonnablement se produire
Il peut être judicieux de convertir les valeurs nulles qui créent @pcolX en types réels de vos colonnes, dans la sous-requête qui crée les variables @pcolX, à savoir:
select @pcol1 := CAST(null as INT), @pcol2 := CAST(null as DATE)
la source
Ce n'est pas la solution la plus robuste - mais si vous cherchez simplement à créer un classement partitionné sur un champ avec seulement quelques valeurs différentes, il peut ne pas être difficile d'utiliser un cas où la logique avec autant de variables que vous le souhaitez.
Quelque chose comme ça a fonctionné pour moi dans le passé:
J'espère que cela a du sens / aide!
la source
Cela fonctionne parfaitement pour moi de créer RowNumber lorsque nous avons plus d'une colonne. Dans ce cas, deux colonnes.
la source
la source
la source