suma de conteo(*) para todas las filas en MySQL
database rdbms (9)
Estoy atascado con la consulta
sum()
donde quiero que la suma de los valores de
count(*)
en todas las filas con
group by
.
Aquí está la consulta:
select
u.user_type as user,
u.count,
sum(u.count)
FROM
(
select
DISTINCT
user_type,
count(*) as count
FROM
users
where
(user_type = "driver" OR user_type = "passenger")
GROUP BY
user_type
) u;
Salida de corriente:
----------------------------------
| user | count | sum |
----------------------------------
| driver | 58 | 90 |
----------------------------------
Rendimiento esperado:
----------------------------------
| user | count | sum |
----------------------------------
| driver | 58 | 90 |
| passenger | 32 | 90 |
----------------------------------
Si
sum(u.count)
de la consulta, la salida se
sum(u.count)
así:
--------------------------
| user | count |
--------------------------
| driver | 58 |
| passenger | 32 |
--------------------------
Agregue una cláusula
group by
al final para
user-type
de
user-type
, por ejemplo:
select
u.user_type as user,
u.count,
sum(u.count)
FROM
(
select
DISTINCT
user_type,
count(*) as count
FROM
users
where
(user_type = "driver" OR user_type = "passenger")
GROUP BY
user_type
) u GROUP BY u.user_type;
Estaría tentado de preguntar; ¿Estás seguro de que necesitas esto en el nivel de DB?
A menos que esté trabajando puramente en la capa de base de datos, cualquier procesamiento de estos resultados se integrará en una capa de aplicación y presumiblemente requerirá algún tipo de bucle a través de los resultados
Podría ser más fácil, más simple y más fácil de ejecutar
SELECT user_type,
COUNT(*) AS count
FROM users
WHERE user_type IN ("driver", "passenger")
GROUP BY user_type
.. y simplemente sume el recuento total en la capa de aplicación
Como lo señaló Juan en otra respuesta, DISTINCT es redundante, ya que GROUP BY garantiza que cada fila resultante sea diferente
Al igual que Juan, también prefiero una IN aquí, en lugar de una condición OR, para el tipo_usuario ya que me resulta más legible. También reduce la posibilidad de confusión si se combinan condiciones adicionales en el futuro.
Además, consideraría mover los nombres de los tipos de usuario, "conductor" y "pasajero" a una tabla separada de tipos de usuarios y hacer referencia a ellos mediante una columna de ID de su tabla de usuarios
NB: Si realmente necesita esto a nivel de base de datos, recomendaría el uso de una de las excelentes opciones de Paul, o el enfoque CROSS JOIN ofrecido por Tom Mac y por Juan como su segunda solución sugerida
Necesitas una subconsulta:
SELECT user_type,
Count(*) AS count,
(SELECT COUNT(*)
FROM users
WHERE user_type IN ("driver","passenger" )) as sum
FROM users
WHERE user_type IN ("driver","passenger" )
GROUP BY user_type ;
Tenga en cuenta que no necesita
distinct
aquí.
O
SELECT user_type,
Count(*) AS count,
c.sum
FROM users
CROSS JOIN (
SELECT COUNT(*) as sum
FROM users
WHERE user_type IN ("driver","passenger" )
) as c
WHERE user_type IN ("driver","passenger" )
GROUP BY user_type ;
Prueba esto. La vista en línea obtiene el total general:
SELECT a.user_type,
count(*) AS count,
b.sum
FROM users a
JOIN (SELECT COUNT(*) as sum
FROM users
WHERE user_type IN ("driver","passenger" )
) b ON TRUE
WHERE a.user_type IN ("driver","passenger" )
GROUP BY a.user_type;
Prueba esto:
WITH SUB_Q AS (
SELECT USER_TYPE, COUNT (*) AS CNT
FROM USERS
WHERE USER_TYPE = "passenger" OR USER_TYPE = "driver"
GROUP BY USER_TYPE
),
SUB_Q2 AS (
SELECT SUM(CNT) AS SUM_OF_COUNT
FROM SUB_Q
)
SELECT A.USER_TYPE, A.CNT AS COUNT, SUB_Q2 AS SUM
FROM SUB_Q JOIN SUB_Q2 ON (TRUE);
Usé el dialecto postgresql pero puede cambiar fácilmente a una subconsulta.
Puedes usar el
modificador
WITH ROLLUP
:
select coalesce(user_type, ''total'') as user, count(*) as count
from users
where user_type in (''driver'', ''passenger'')
group by user_type with rollup
Esto devolverá la misma información pero en un formato diferente:
user | count
----------|------
driver | 32
passenger | 58
total | 90
En MySQL 8 puedes usar
COUNT()
como
función de ventana
:
select distinct
user_type,
count(*) over (partition by user_type) as count,
count(*) over () as sum
from users
where user_type in (''driver'', ''passenger'');
Resultado:
user_type | count | sum
----------|-------|----
driver | 32 | 90
passenger | 58 | 90
o use CTE (Expresiones de tabla comunes) :
with cte as (
select user_type, count(*) as count
from users
where user_type in (''driver'', ''passenger'')
group by user_type
)
select user_type, count, (select sum(count) from cte) as sum
from cte
Simplemente puede combinar
SUM() OVER()
con
COUNT(*)
:
SELECT user_type, COUNT(*) AS cnt, SUM(COUNT(*)) OVER() AS total
FROM users WHERE user_type IN (''driver'', ''passenger'') GROUP BY user_type;
Salida:
+------------+------+-------+
| user_type | cnt | total |
+------------+------+-------+
| passenger | 58 | 90 |
| driver | 32 | 90 |
+------------+------+-------+
Tom Mac Explica correctamente tu respuesta. Aquí está la otra forma en que puedes hacer eso. Verifico el rendimiento de la consulta y no encontré ninguna diferencia dentro de 1000 registros
select user_type,Countuser,(SELECT COUNT(*)
FROM users
WHERE user_type IN (''driver'',''passenger '') )as sum from (
select user_type,count(*) as Countuser from users a
where a.user_type=''driver''
group by a.user_type
union
select user_type,count(*) as Countuser from users b
where b.user_type=''passenger''
group by b.user_type
)c
group by user_type,Countuser
select
u.user_type as user,
u.count,
sum(u.count)
FROM users group by user