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.

¿Fue útil?

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 
Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top