Comment compter et limiter l'enregistrement dans une requête unique dans MYSQL?

StackOverflow https://stackoverflow.com/questions/802373

  •  03-07-2019
  •  | 
  •  

Question

Je recherche des enregistrements dans une table comme suit:

SELECT Id, Name FROM my_table WHERE Name LIKE '%prashant%' LIMIT 0, 10;

Maintenant, j'ajoute LIMIT pour gérer ma pagination. Mais lorsque l'utilisateur recherche le mot "prashant", le nombre total d'enregistrements que j'ai est égal à 124 pour "prashant". Mais comme la limite appliquée à la requête, elle ne récupère que 10 enregistrements dans mon script PHP et lorsque je compte la variable mysql dans le code PHP, le nombre total d'enregistrements trouvés est 10.

Donc, fondamentalement, je veux compter et limiter en utilisant une requête unique, en apportant quelques modifications à la requête ci-dessus, je veux le nombre total (124) d'enregistrements. Je ne souhaite pas exécuter une requête de décompte séparée (*) uniquement pour compter le résultat total trouvé par la requête.

Merci.

Était-ce utile?

La solution

SELECT SQL_CALC_FOUND_ROWS
  Id, Name
FROM my_table
WHERE
  Name LIKE '%prashant%'
LIMIT 0, 10;

# Find total rows
SELECT FOUND_ROWS();

plus d'infos

Autres conseils

MySQL prend en charge cette opération avec SQL_CALC_FOUND_ROWS comme mentionné par Ionut. Cependant, il s'avère que dans de nombreux cas il est en fait plus rapide de le faire à l'ancienne en utilisant deux instructions, dont l'une est un count () . Cela nécessite toutefois que le comptage puisse être effectué à l'aide d'un balayage d'index, ce qui ne sera pas le cas pour cette requête, mais j'ai pensé que je le mentionnerais quand même.

C’est pour les autres personnes ayant le même besoin (étant donné que cela fait 3 ans à partir de la date de cette question).

J'avais un problème similaire et je ne voulais pas créer 2 requêtes. J'ai donc créé une colonne supplémentaire pour le nombre total et déplacé les clauses LIMIT et OFFSET à la fin:

SELECT SQL_CALC_FOUND_ROWS * FROM (
    SELECT `id`, `name`
    FROM `my_table`
    WHERE `name` LIKE '%prashant%'
) res,
(SELECT /*CEIL(FOUND_ROWS()/10) AS 'pages',*/ FOUND_ROWS() AS 'total') tot
LIMIT 0, 10

Donc, le résultat est quelque chose comme

| id  |      name      | total |
+-----+----------------+-------+
|  1  | Jason Prashant |  124  |
|  2  | Bob Prashant   |  124  |
|  3  | Sam Prashant   |  124  |
|  4  | etc. prashant  |  124  |

et je pense que cette solution n'a pas d'inconvénient en termes de synchronisation car elle extrait le résultat une seule fois, puis utilise le nombre de lignes déjà calculé pour la colonne supplémentaire.

En cas d'énormes tables et de la sélection de plusieurs champs (pas seulement Id, Name comme dans votre exemple), je vous recommande d'utiliser 2 requêtes. Sélectionnez count (0) en premier avec toutes ces clauses WHERE, puis construisez ensuite la pagination, en sélectionnant les données, etc. Cela fonctionnera très rapidement sur certains sites Web de commerce électronique populaires, par exemple.

N'utilisez pas SQL_CALC_FOUND_ROWS et FOUND_ROWS ()

  1. il y a les bugs rapportés
    ici: https://bugs.mysql.com/bug.php?id=18454
    et ici: https://bugs.mysql.com/bug.php?id=19553

  2. alors que sur de petites tables, BENCHMARK dépend d’autres choses et le temps que prendra votre SELECT sera à peu près identique à COUNT (0) - SQL_CALC_FOUND_ROWS impose toujours des restrictions aux optimisations de base de données LIMIT et ORDER BY dépend d'eux n'utilisez pas SQL_CALC_FOUND_ROWS

  3. sur les grandes tables, la différence au niveau de BENCHMARK devient énorme, où COUNT (0) peut prendre 0,003 seconde, le même SQL_CALC_FOUND_ROWS pourrait maintenant prendre 20 secondes

Par toutes les métrices, COUNT (0) est le choix supérieur

SYNTHÈSE COUNT (0):

(SELECT COUNT(0) FROM tableNames WHERE condition) AS alias
// alias is optional but needed if you need to use the result later

Ainsi, votre requête totale ressemblerait à ceci

(SELECT COUNT(0) FROM my_table WHERE name LIKE '%prashant%') AS countResults;

SELECT Id, Name FROM my_table WHERE Name LIKE '%prashant%' LIMIT 0, 10;

Et appelez simplement countResults partout où vous en avez besoin ailleurs ...

Un autre avantage de COUNT (0) est que vous pouvez l’utiliser pour effectuer une recherche dans la même table ou ici, ou pour rechercher une autre table ...

Ainsi, par exemple, si chaque personne trouvée possède également 3, 2, 1, 5 emplois différents, vous pouvez simplement ajouter un

(SELECT COUNT(0) FROM my_jobs_table WHERE name = name_row_in_jobs_table) AS jobs

dans votre SELECT d'origine comme ceci

SELECT Id, Name (SELECT COUNT(0) FROM my_jobs_table WHERE name = name_row_in_jobs_table) AS jobs FROM my_table WHERE Name LIKE '%prashant%' LIMIT 0, 10;

vous donnant:

--------------------
| id | Name | jobs |
--------------------
| 1  | Alice| 3    |
--------------------
| 2  | John | 2    |
--------------------
| 3  | Bob  | 1    |
--------------------
| 4  | Jill | 5    |
--------------------

Ainsi, lorsque vous indiquez le nom [3] (c.-à-d. Bob), vous pouvez également indiquer que Bob a 1 travail en appelant des travaux [3] ...

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top