Comment l'utilisation réelle de nombre de ligne (COUNT(*)) dans la clause where sans écrire de la même requête que la sous-requête?
J'ai quelque chose comme ceci:
SELECT id, fruit, pip
FROM plant
WHERE COUNT(*) = 2;
Cette étrange requête est auto-explicatif, je suppose. COUNT(*)
signifie ici le nombre de lignes dans plant
table. Mon exigence est que j'ai besoin de récupérer des valeurs dans les champs spécifiés seulement si le nombre total de lignes dans la table = 2. Cela ne fonctionne pas, mais: invalid use of aggregate function COUNT
.
Je ne peux pas faire ceci:
SELECT COUNT(*) as cnt, id, fruit, pip
FROM plant
WHERE cnt = 2;
d'une part, il limite le nombre de lignes de sortie à 1, et de deux, elle donne le même message d'erreur: invalid use of aggregate function
.
Ce que je peux faire, c'est plutôt:
SELECT id, fruit, pip
FROM plant
WHERE (
SELECT COUNT(*)
FROM plant
) = 2;
Mais alors que la sous-requête est la principale requête ré-exécuter. Je vais présenter ici un petit exemple de la plus grande partie du problème, même si je sais supplémentaires COUNT(*)
sous-requête dans l'exemple donné n'est pas un grand un rétroprojecteur.
Edit: je ne sais pas pourquoi la question est downvoted. Le COUNT(*)
je suis en train d'essayer d'obtenir à partir d'une vue (une table temporaire) dans la requête, qui est une grande requête avec 5 à 6 jointures supplémentaires et les clauses where. Pour ré-exécuter la requête comme une sous-requête pour obtenir le nombre est inefficace, et je peux voir le goulot d'étranglement.
Voici la requête:
SELECT U.UserName, E.Title, AE.Mode, AE.AttemptNo,
IF(AE.Completed = 1, 'Completed', 'Incomplete'),
(
SELECT COUNT(DISTINCT(FK_QId))
FROM attempt_question AS AQ
WHERE FK_ExcAttemptId = @excAttemptId
) AS Inst_Count,
(
SELECT COUNT(DISTINCT(AQ.FK_QId))
FROM attempt_question AS AQ
JOIN `question` AS Q
ON Q.PK_Id = AQ.FK_QId
LEFT JOIN actions AS A
ON A.FK_QId = AQ.FK_QId
WHERE AQ.FK_ExcAttemptId = @excAttemptId
AND (
Q.Type = @descQtn
OR Q.Type = @actQtn
AND A.type = 'CTVI.NotImplemented'
AND A.IsDelete = @status
AND (
SELECT COUNT(*)
FROM actions
WHERE FK_QId = A.FK_QId
AND type != 'CTVI.NotImplemented'
AND IsDelete = @status
) = 0
)
) AS NotEvalInst_Count,
(
SELECT COUNT(DISTINCT(FK_QId))
FROM attempt_question AS AQ
WHERE FK_ExcAttemptId = @excAttemptId
AND Mark = @mark
) AS CorrectAns_Count,
E.AllottedTime, AE.TimeTaken
FROM attempt_exercise AS AE
JOIN ctvi_exercise_tblexercise AS E
ON AE.FK_EId = E.PK_EId
JOIN ctvi_user_table AS U
ON AE.FK_UId = U.PK_Id
JOIN ctvi_grade AS G
ON AE.FK_GId = G.PK_GId
WHERE AE.PK_Id = @excAttemptId
-- AND COUNT(AE.*) = @number --the portion in contention.
De bien vouloir ignorer la requête ci-dessus et de me guider vers la droite en direction de la petite exemple de requête que j'ai posté, merci.
COUNT()
contre une table entière, la plupart des moteurs (MySQL et PostgreSQL pour sûr, mais je pense que SQLite trop) de récupérer la table de cardinalité en O(1) à partir des métadonnées de la table. COUNT()
devient un problème si vous l'exécutez avec un OÙ sur une clause de non indexées. Remplacement de la simple COUNT()
avec une JOINTURE ou d'une autre "truc" pourrait même ralentir la requête.MySQL n'est pas SqlLite
Lisez la dernière phrase de ma question. Avez-vous sérieusement pense que je vais simplement essayer d'obtenir le nombre à partir d'une table? La requête j'ai dans mon code est un peu complexe, avec 5 à 6 jointures et les clauses where. Pour la sous-requête, il n'est pas seulement peu élégante, mais très inefficace. En outre, je ne suis même pas de la récupération de la fonction count(*) valeur à partir d'une table, mais une situation temporaire dans la requête.
c'est vraiment pas, qui le dire? En attendant, ce qui est SqlLite? 😉
Le
SELECT COUNT(*) FROM BaseTable
va s'exécuter en O(1) seulement en MyISAM moteur de MySQL, pas en InnoDB. Et bien sûr, uniquement pour les tables de base, pas les vues ou les tables dérivées.
OriginalL'auteur nawfal | 2012-10-28
Vous devez vous connecter pour publier un commentaire.
Dans MySQL, vous ne pouvez faire ce que vous avez essayé:
ou de cette variation:
Si le 1er ou le 2ème est plus efficace, dépend de la version de MySQL (et l'optimiseur). Je serais prêt à parier sur le 2ème, sur la plupart des versions.
Dans d'autres Sgbd, qui ont des fonctions de la fenêtre, vous pouvez également faire la première requête que @Andomar suggère.
Voici une suggestion pour éviter le goulot d'étranglement de calcul de la dérivée de la table, une fois pour obtenir les lignes et une fois de plus pour obtenir le nombre. Si la table dérivée est cher pour être calculé, et ses lignes sont des milliers, voire des millions, de calculer deux fois seulement à jeter, c'est un problème, en effet. Cela peut améliorer l'efficacité, il permettra de limiter les intermédiaires (deux fois) de lignes calculées à 3:
Pour éviter l'extraction de deux fois le milliers (ou millions) de lignes de la table dérivée. Il n'est pas question pour vous, si ils sont 3 ou 3000 ou 1000000, droit? Vous n'en voulez pas si ils sont 3 ou plus.
Haha, qui semble être de manière innovante, j'obtiens ça 🙂
Pouvez-vous partager les détails sur les horaires des différentes requêtes?
J'ai fait quelques tests avec quelques milliers d'enregistrements. Ils ont tous effectué plus ou moins la même chose! Si vous souhaitez une précision d'orfèvre après un certain nombre de tests, le voici: Le dernier que vous avez posté (avec des limites) effectuées marginalement bien avec chaque requête qui prend environ 300ms. Les premier et deuxième blocs de code ont été idem identiques, mais pour un sèche-largeur gagner sql1 battre sql2 par un score de 305 ms à 308 ms!!
OriginalL'auteur ypercubeᵀᴹ
Après re-lecture de votre question, vous essayez de renvoyer les lignes que si il y a 2 lignes dans la table entière. Dans ce cas, je pense que votre propre exemple de requête est déjà le meilleur.
Sur un autre SGBD, vous pouvez utiliser une fonction de Fenêtrage:
Mais la
over
clause n'est pas pris en charge sur MySQL.tort anser ci-dessous
La
where
clause œuvres d'avant le regroupement. Il fonctionne sur des lignes simples, pas de groupes de lignes, de sorte que vous ne pouvez pas utiliser des agrégats commecount
oumax
dans lewhere
clause.Pour définir des filtres qui fonctionnent sur des groupes de lignes, utilisez la
having
clause. Il fonctionne après regroupement et peut être utilisé pour filtrer avec des agrégats:Ando, oui et donc j'ai annulé mon vote. laissez-moi voir encore une fois votre modifier
Comme je l'ai mentionné, en faire une sous-requête est si peu élégante et peut être inefficace avec 5 à 6 rejoint et où l'une des clauses déjà en cours d'exécution sur la requête principale.
Dans MYSQL, si vous utilisez
count
sansgroup by
, MySQL groupes sur l'ensemble vide. Il sera de retour une seule ligne. Donc, autant que je sache, vous ne pouvez pas obtenir le total du nombre de lignes et de plus d'une ligne dans la même requête.+1 pour montrer de la compassion à patauger dans l'abondante et largement hors de propos contenu dans la question
OriginalL'auteur Andomar
Les autres réponses ne répondent pas à la question initiale qui était de filtrer les résultats "sans l'aide d'une sous-requête".
Vous pouvez faire cela en utilisant une variable dans 2 consécutifs MySQL états:
Je ne suis pas sûr de l'efficacité des coûts, mais je pense que la meilleure approche est de n'être concerné avec efficacité lorsque vous rencontrez des goulets d'étranglement. Jusqu'alors, à mon avis, la lisibilité et la maintenabilité est prioritaire et ayant des sous-requêtes crée une complexité inutile.
OriginalL'auteur Stack Man