2008-10-27 20 views
39

Tengo una tabla que tiene una columna processed_timestamp - si se ha procesado un registro, ese campo contiene la fecha y hora en que se procesó; de lo contrario, es nulo.¿Cómo devuelvo mis registros agrupados por NULL y NOT NULL?

Quiero escribir una consulta que devuelve dos filas:

NULL  xx -- count of records with null timestamps 
NOT NULL yy -- count of records with non-null timestamps 

es posible?

Actualización: La tabla es bastante grande, por lo que la eficiencia es importante. Podría simplemente ejecutar dos consultas para calcular cada total por separado, pero quiero evitar golpear la mesa dos veces si puedo evitarlo.

Respuesta

18

Oracle:

grupo por NVL2 (campo, 'NOT NULL', 'NULL')

+0

Sweet - es una función personalizada ingeniosa. (Más aquí: http://www.java2s.com/Code/Oracle/Char-Functions/NVL2xvalue1value2Returnsvalue1ifxisnotnullifxisnullvalue2revuelta.htm) –

42

En MySQL que podría hacer algo como

SELECT 
    IF(ISNULL(processed_timestamp), 'NULL', 'NOT NULL') as myfield, 
    COUNT(*) 
FROM mytable 
GROUP BY myfield 
+0

Esto es impresionante, tengo que jugar con el alguna condicional IF más –

+0

La mejor respuesta para MySQL. – marijnz0r

5

Si se trata de Oracle, puede hacerlo:

select decode(field,NULL,'NULL','NOT NULL'), count(*) 
from table 
group by decode(field,NULL,'NULL','NOT NULL'); 

Estoy seguro de que otros DBs permiten truco similar.

20

Intente lo siguiente, que es independiente del proveedor:

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 tener nuestra mirada gurú de DB2 local en esto, él está de acuerdo: ninguna de las soluciones presentadas hasta la fecha (incluido éste) puede evitar una mesa llena escanear (de la tabla si la marca de tiempo no está indexada, o del indexotherwise). Todos escanean cada registro en la tabla exactamente una vez.

Todas las soluciones CASE/IF/NVL2() hacen una conversión de nulo a cadena para cada fila, introduciendo una carga innecesaria en el DBMS. Esta solución no tiene ese problema.

+0

Esta es una mesa bastante grande, golpearla dos veces es ineficiente, ¿no? –

+0

No, en realidad (al menos en DB2, que es el DB que uso), esta solución será tan rápida como todas las de tipo decodificación/nvl2; todas tienen que realizar un escaneo de tabla completo (mi solución procesará el mismo número de los registros en general, pero en dos grupos) - índice en el campo de marca de tiempo en ambos casos. – paxdiablo

+0

Será interesante probar esta solución de lado a lado con la de un proveedor específico cuando llegue a trabajar mañana. –

31

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 
0

Otro MySQL método es utilizar la CASE operator, que se puede generalizar 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 
+0

La función IF() funciona igual - if (processed_timestamp es nulo, 'nulo', 'no nulo') – pilsetnieks

0

personalmente me gusta la solución de Pax, pero si requiere absolutamente una sola fila devuelta (ya que tuve hace poco), En MS SQL Server 2005/2008 puede "apilar" las dos consultas usando 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 

Esperanza esta ayuda

+0

Pero luego está golpeando dos veces la base de datos: ineficiente. (Que debe ser el motivo por el cual Pax eliminó su solución.) –

+0

Aproximación bastante grande para un problema tan simple, ¿no? – Tomalak

+0

Solo está presionando dos veces la base de datos si su base de datos no la optimiza. Probablemente una suposición segura, pero una suposición, no obstante. – Tanktalus

0

[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 se puede añadir a la declaración de caso cualesquiera otros valores que desea formar una partición, por ejemplo, hoy, ayer, entre el mediodía y las 2 p. m., después de las 6 p.m. del jueves.

5

Stewart,

consideran Tal vez esta solución. Es (también!) Vendedor no específico.

SELECT count([processed_timestamp]) AS notnullrows, 
     count(*) - count([processed_timestamp]) AS nullrows 
FROM table 

En cuanto a la eficiencia, esto evita 2x búsquedas de índice/escaneos de tabla/lo que sea al incluir los resultados en una fila. Si absolutamente requiere 2 filas en el resultado, dos pases sobre el conjunto pueden ser inevitables debido a los agregados de unión.

Esperanza esto ayuda

0
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 leyó con cuidado, éste devuelve una sola fila.

0

En Oracle

SELECT COUNT(*), COUNT(TIME_STAMP_COLUMN) 
FROM TABLE; 

cuenta (*) devuelve el recuento de todas las filas

count (column_name) devuelve el número de filas que no son NULL, por lo

SELECT COUNT(*) - COUNT(TIME_STAMP_COLUMN) NUL_COUNT, 
        COUNT(TIME_STAMP_COLUMN) NON_NUL_COUNT 
FROM TABLE 

debe para hacer el trabajo.

Si la columna está indexada, es posible que termine con algún tipo de escaneo de rango y evite leer realmente la tabla.

1

Si su base de datos tiene una función COUNT (*) eficiente para una tabla, puede CONVERTIR el que sea menor y restar.

1

SQL Server (a partir de 2012):

SELECT IIF(ISDATE(processed_timestamp) = 0, 'NULL', 'NON NULL'), COUNT(*) 
FROM MyTable 
GROUP BY ISDATE(processed_timestamp); 
0

Otra forma de T-SQL (SQL-servidor)

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