Pregunta

Tengo una consulta como esta:

SELECT t1.id,
    (SELECT COUNT(t2.id)
     FROM t2
     WHERE t2.id = t1.id
          ) as num_things
FROM t1
WHERE num_things = 5;

El objetivo es obtener la identificación de todos los elementos que aparecen 5 veces en la otra tabla. Sin embargo, recibo este error:

ERROR: column "num_things" does not exist
SQL state: 42703

Probablemente estoy haciendo algo tonto aquí, ya que soy algo nuevo en las bases de datos. ¿Hay alguna manera de arreglar esta consulta para que pueda acceder a num_things ? O, si no, ¿hay alguna otra forma de lograr este resultado?

¿Fue útil?

Solución

Creo que podría reescribir su consulta así:

SELECT t1.id
FROM t1
WHERE (SELECT COUNT(t2.id)
     FROM t2
     WHERE t2.id = t1.id
          ) = 5;

Otros consejos

Algunos puntos importantes sobre el uso de SQL:

  • No puede usar alias de columna en la cláusula WHERE, pero sí puede hacerlo en la cláusula HAVING. Esa es la causa del error que recibió.
  • Puede contar mejor utilizando JOIN y GROUP BY que utilizando subconsultas correlacionadas. Será mucho más rápido.
  • Use la cláusula HAVING para filtrar grupos.

Esta es la forma en que escribiría esta consulta:

SELECT t1.id, COUNT(t2.id) AS num_things
FROM t1 JOIN t2 USING (id)
GROUP BY t1.id
HAVING num_things = 5;

Me doy cuenta de que esta consulta puede omitir JOIN con t1, como en la solución de Charles Bretana. Pero supongo que es posible que desee que la consulta incluya algunas otras columnas de t1.


Re: la pregunta en el comentario:

La diferencia es que la cláusula WHERE se evalúa en las filas, antes de que GROUP BY reduzca los grupos a una sola fila por grupo. La cláusula HAVING se evalúa después de que se forman los grupos. Por lo tanto, no puede, por ejemplo, cambiar el COUNT () de un grupo utilizando HAVING ; solo puede excluir el grupo en sí.

SELECT t1.id, COUNT(t2.id) as num
FROM t1 JOIN t2 USING (id)
WHERE t2.attribute = <value>
GROUP BY t1.id
HAVING num > 5;

En la consulta anterior, WHERE filtra las filas que coinciden con una condición y HAVING filtra los grupos que tienen al menos cinco cuentas.

El punto que causa confusión a la mayoría de las personas es cuando no tienen una cláusula GROUP BY , por lo que parece como HAVING y < code> WHERE son intercambiables.

WHERE se evalúa antes de las expresiones en la lista de selección. Esto puede no ser obvio porque la sintaxis SQL pone primero la lista de selección. Por lo tanto, puede ahorrar una gran cantidad de cálculos costosos utilizando WHERE para restringir las filas.

SELECT <expensive expressions>
FROM t1
HAVING primaryKey = 1234;

Si usa una consulta como la anterior, las expresiones en la lista de selección se calculan para cada fila , solo para descartar la mayoría de los resultados debido al HAVING condición. Sin embargo, la siguiente consulta calcula la expresión solo para la fila única que coincide con la condición WHERE .

SELECT <expensive expressions>
FROM t1
WHERE primaryKey = 1234;

Entonces, para recapitular, el motor de la base de datos ejecuta las consultas de acuerdo con una serie de pasos:

  1. Genera un conjunto de filas de la (s) tabla (s), incluidas las filas producidas por JOIN .
  2. Evalúe las condiciones de WHERE contra el conjunto de filas, filtrando las filas que no coinciden.
  3. Calcule expresiones en select-list para cada una en el conjunto de filas.
  4. Aplicar alias de columna (tenga en cuenta que este es un paso separado, lo que significa que no puede usar alias en expresiones en la lista de selección).
  5. Condensar grupos en una sola fila por grupo, de acuerdo con la cláusula GROUP BY .
  6. Evalúe las condiciones de HAVING contra grupos, filtrando los grupos que no coinciden.
  7. Ordenar resultado, de acuerdo con la cláusula ORDER BY .

Todas las otras sugerencias funcionarían, pero para responder a su pregunta básica sería suficiente escribir

  SELECT id  From T2
  Group By Id
  Having Count(*) = 5

Me gustaría mencionar que en PostgreSQL no hay forma de usar una columna con alias para tener una cláusula.

es decir,

SELECCIONE usr_id COMO my_id DEL usuario QUE TIENE my_id = 1

No funcionará.

Otro ejemplo que no va a funcionar:

SELECCIONE su.usr_id AS my_id, COUNT (*) AS val FROM sys_user AS su GROUP BY su.usr_id HAVING val > = 1

Habrá el mismo error: no se conoce la columna val.

Estoy destacando esto porque Bill Karwin escribió algo que no es realmente cierto para Postgres:

" No puede usar alias de columna en la cláusula WHERE, pero sí puede hacerlo en la cláusula HAVING. Esa es la causa del error que recibió. & Quot;

prueba esto

SELECT t1.id,
    (SELECT COUNT(t2.id) as myCount
     FROM t2
     WHERE t2.id = t1.id and myCount=5
          ) as num_things
FROM t1
Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top