Consulta SQL con NULLS

dagavi

Acudo una vez más a vosotros (últimamente lo hago demasiado xD) para postear una duda sobre como realizar una consulta SQL.

Concretamente tenemos una tabla que tiene un atributo que puede ser NULL, T(id, atrib)

Realizar una consultar SQL que cuente los diferentes valores de atrib, incluyendo el NULL como 1.

Es decir, si excluimos el concepto de NULL sería algo tal que:

SELECT COUNT(DISTINCT atrib)
FROM T

Si añadimos NULL se puede resolver así:

SELECT COUNT(*)
FROM (SELECT DISTINCT atrib
           FROM T)

¿Dónde está el problema? En que no nos dejan meter un SELECT dentro del FROM, por lo que no se como cojones contar el "+1" si hay alguna fila con valor NULL.

tOWERR

Existe una función que es NVL(campo,valor). Esta función lo que hace es que a los valores NULL del campo que le indicas le pone el valor que quieras. Por ejemplo:
SELECT count(*),NVL(id,1)
FROM tabla;

Lo que hace es a los valores NULL del campo 'id' los asigna el valor 1.
Nose si es a eso a lo que te refieres.
Un saludo.

dagavi

No, aunque tampoco lo podría usar (tienen que ser consultas estándar y "básicas", no puedo usar eso)

La cosa sería que si en la tabla tenemos:

atrib

1
1
2
NULL
NULL
NULL
NULL

El resultado es 3, ya que hay 3 valores de atrib: 1, 2 y NULL (vamos, el count distinct de toda la vida pero que incluya el NULL, pero se debería calcular, no se permite ejecutar algo que lo haga directamente)

PD: Eso me valdría si asignara un valor fuera del rango (que puedo hacerlo) ya que entonces el COUNT(DISTINCT) vería un valor y haría "+1" al resultado, pero ya digo que no me dejan xD

NeB1

#3 esto supongo que no funciona, no?

SELECT COUNT(*) FROM T GROUP BY attrib

Pensandolo bien, aunque contase bien a los nuls, te devolvería

2
1
4

a lo mejor un SELECT ROW_COUNT() FROM T GROUP BY attrib

(suponiendo que usas mysql y una versión superior a la 5.0.1)

dagavi

Como bien comentas, no, no funciona xD

Ya lo he sacado, la consulta es bastante más compleja (al menos lo que se me ha ocurrido).

La tabla real del enunciado, que aquí simplifique a un ID y el atributo, tiene, entre otras cosas que no vienen a caso, una prinary key compuesta por dos atributos, ambos integers y el atributo en cuestión, también integer y con posibilidad de NULL.

Como por lo que nos obligan a hacer era casi de cajón que la consulta tenía que empezar como:

SELECT COUNT(*) y esto tenía que retornar el resultado, el problema estaba en generar 1 fila por cada valor de atributo, pero para ello he seguido la siguiente estrategia:

He obtenido una tupla representante de cada valor diferente de atrib. Concretamente, por cada valor de atrib escogía la tupla con mayor valor del primer atributo de la PK y, posteriormente, mayor valor del segundo atributo de la PK. Con esto tenemos 1 fila por cada valor del atributo y la consulta se esquematiza en algo como:

SELECT COUNT(*)
FROM T
WHERE // comprobar que la fila es una de las filas representantes

Para esto básicamente miraba que:

valor1 IN (SELECT MAX(t2.valor1)
                           FROM T t2
                           GROUP BY t2.atrib)

Ahora sabemos que, como mínimo, la fila tiene un valor1 que pertenece a una de las filas candidatas, solo falta comprobar vía valor2 si realmente lo es

valor2 IN (SELECT MAX(t2.valor2)
                           FROM T t2
                           WHERE t2.valor1 = valor1 AND
                                        NOT EXISTS (/* Comprobar que esta fila realmente es la representante
                                                                mirando que no haya filas con mayor valor1 y con mismo
                                                                valor de atrib que t2.atrib */)
                           GROUP BY t2.atrib)

La de mierdas que hay que hacer solo por no dejar usar ciertas cosas, un código que se puede resolver con un triste:

SELECT COUNT(*)
FROM (SELECT DISTINCT atrib FROM T)

LOc0

Viendo tu solución no me termina de quedar claro lo de consultas "básicas" (¿no usar tablas derivadas?) pero creo que:

SELECT count(distinct atrib) + (select count(*) from tabla where atrib=NULL limit 1) from tabla

también debería funcionar.

El objetivo didáctico de estos ejercicios rollo "está-prohibido" nunca lo he pillado del todo. Esto tiene poco que ver con bases de datos y para ejercitar la mente veo más entretenido un sudoku...

Tampoco entiendo por qué select distinct atrib incluye el null y count(distinct atrib) no (esto tengo que reconocer que lo acabo de mirar).

Salu2 ;)

dagavi

Básicamente nos dejan hcer SELECT, subconsultas solo en el WHERE y HAVING y hacer group by y order.

El límit no se puede usar, si quieres una fila te lo tienes que trabajar para obtenerla de otra forma.

Ayer estaba ya saturado y al final me salió esa forma, pero un poco "rebuscada", se puede hacer lo mismo de forma más sencilla así:

SELECT COUNT(*)
FROM T t
WHERE t.valor1 = (SELECT MAX(t2.valor1)
                  FROM T t2
                  WHERE (t2.atrib IS NULL and t.atrib IS NULL)
                     OR t2.atrib = t.atrib)
  AND t.valor2 = (SELECT MAX(t2.valor2)
                  FROM T t2
                  WHERE t2.valor1 = t.valor1 AND
                         ((t2.atrib IS NULL and t.atrib IS NULL)
                           OR t2.atrib = t.atrib))

No hacía falta trabajar con conjuntos y "IN", se puede consultar valores exactos xD

Usuarios habituales

  • dagavi
  • LOc0
  • NeB1
  • tOWERR