¿Cómo devuelvo mis registros agrupados por NULL y NOT NULL?
Pregunta
Tengo una tabla que tiene una columna processor_timestamp
: si se ha procesado un registro, ese campo contiene la fecha y hora en que se procesó, de lo contrario es nulo.
Quiero escribir una consulta que devuelva dos filas:
NULL xx -- count of records with null timestamps
NOT NULL yy -- count of records with non-null timestamps
¿Es eso posible?
Actualización: La tabla es bastante grande, por lo que la eficiencia es importante. Podría ejecutar dos consultas para calcular cada total por separado, pero quiero evitar golpear la mesa dos veces si puedo evitarlo.
Solución
Oracle:
agrupar por nvl2 (campo, 'NOT NULL', 'NULL')
Otros consejos
En MySQL puedes hacer algo como
SELECT
IF(ISNULL(processed_timestamp), 'NULL', 'NOT NULL') as myfield,
COUNT(*)
FROM mytable
GROUP BY myfield
En T-SQL (MS SQL Server), esto funciona:
SELECT
CASE WHEN Field IS NULL THEN 'NULL' ELSE 'NOT NULL' END FieldContent,
COUNT(*) FieldCount
FROM
TheTable
GROUP BY
CASE WHEN Field IS NULL THEN 'NULL' ELSE 'NOT NULL' END
Pruebe lo siguiente, es neutral con respecto a los proveedores:
select
'null ' as type,
count(*) as quant
from tbl
where tmstmp is null
union all
select
'not null' as type,
count(*) as quant
from tbl
where tmstmp is not null
Después de que nuestro gurú de DB2 local vea esto, está de acuerdo: ninguna de las soluciones presentadas hasta la fecha (incluida esta) puede evitar un análisis completo de la tabla (de la tabla si la marca de tiempo no está indexada, o del índice de lo contrario). Todos escanean cada registro en la tabla exactamente una vez.
Todas las soluciones CASE / IF / NVL2 () realizan una conversión de nulo a cadena para cada fila, lo que introduce una carga innecesaria en el DBMS. Esta solución no tiene ese problema.
Si es oráculo, entonces puedes hacerlo:
select decode(field,NULL,'NULL','NOT NULL'), count(*)
from table
group by decode(field,NULL,'NULL','NOT NULL');
Estoy seguro de que otras bases de datos permiten trucos similares.
Stewart,
Tal vez considere esta solución. Es (¡también!) Proveedor no específico.
SELECT count([processed_timestamp]) AS notnullrows,
count(*) - count([processed_timestamp]) AS nullrows
FROM table
En cuanto a la eficiencia, esto evita búsquedas de índice 2x / exploraciones de tabla / lo que sea, incluyendo los resultados en una fila. Si necesita absolutamente 2 filas en el resultado, dos pasadas sobre el conjunto pueden ser inevitables debido a los agregados de unión.
Espero que esto ayude
Otro método MySQL es utilizar CASE
operador , que puede generalizarse a más alternativas que IF ()
:
SELECT CASE WHEN processed_timestamp IS NULL THEN 'NULL'
ELSE 'NOT NULL' END AS a,
COUNT(*) AS n
FROM logs
GROUP BY a
Si su base de datos tiene una función COUNT (*) eficiente para una tabla, podría CUENTAR el que sea el número más pequeño y restar.
SQL Server (a partir de 2012):
SELECT IIF(ISDATE(processed_timestamp) = 0, 'NULL', 'NON NULL'), COUNT(*)
FROM MyTable
GROUP BY ISDATE(processed_timestamp);
Personalmente, me gusta la solución de Pax, pero si absolutamente necesita que solo se devuelva una fila (como lo había hecho recientemente), en MS SQL Server 2005/2008 puede " apilar " las dos consultas utilizando un CTE
with NullRows (countOf)
AS
(
SELECT count(*)
FORM table
WHERE [processed_timestamp] IS NOT NULL
)
SELECT count(*) AS nulls, countOf
FROM table, NullRows
WHERE [processed_timestamp] IS NULL
GROUP BY countOf
Espero que esto ayude
[T-SQL]:
select [case], count(*) tally
from (
select
case when [processed_timestamp] is null then 'null'
else 'not null'
end [case]
from myTable
) a
Y puedes agregar a la declaración del caso cualquier otro valor que desees para formar una partición, por ejemplo. hoy, ayer, entre el mediodía y las 2pm, después de las 6pm de un jueves.
Select Sum(Case When processed_timestamp IS NULL
Then 1
Else 0
End) not_processed_count,
Sum(Case When processed_timestamp Is Not NULL
Then 1
Else 0
End) processed_count,
Count(1) total
From table
Editar: no se leyó con cuidado, este devuelve una sola fila.
En Oracle
SELECT COUNT(*), COUNT(TIME_STAMP_COLUMN)
FROM TABLE;
count (*) devuelve el recuento de todas las filas
count (column_name) devuelve el número de filas que no son NULL, por lo que
SELECT COUNT(*) - COUNT(TIME_STAMP_COLUMN) NUL_COUNT,
COUNT(TIME_STAMP_COLUMN) NON_NUL_COUNT
FROM TABLE
debe hacer el trabajo.
Si la columna está indexada, podría terminar con algún tipo de escaneo de rango y evitar realmente leer la tabla.
Otra forma en T-sql (sql-server)
select count(case when t.timestamps is null
then 1
else null end) NULLROWS,
count(case when t.timestamps is not null
then 1
else null end) NOTNULLROWS
from myTable t