2012-09-02 54 views
14

Estoy intentando hacer una consulta con postgresql. La base de datos contiene dos relaciones: "reino", que incluye algunos reyes ingleses, y "dinastía", que contiene algunas personas de la dinastía stuartSQL: la subconsulta tiene demasiadas columnas

La relación "reino" incluye el nombre del rey y cuándo comenzó y terminó su reino . La relación "dinastía" incluye nombre, género, nacimiento y muerte.

Lo que estoy tratando de consultar es el rey que era el más viejo cuando murió.

Con mi consulta que estoy recibiendo este error en la línea 3 (NO EN): subquery has too many columns

Esta es la consulta:

SELECT kingdom.king, dinasty.birth, dinasty.death 
FROM kingdom, dinasty 
WHERE kingdom.king = dinasty.name AND kingdom.king NOT IN 
(
    SELECT DISTINCT R1.king, R1.birth, R1.death 
    FROM 
    (
     SELECT DISTINCT R1.king, D1.birth, D1.death 
     FROM kingdom AS R1, dinasty AS D1, dinasty AS D2 
     WHERE R1.king=D1.name 
    ) AS R1, 
    (
     SELECT DISTINCT R1.king, D1.birth, D1.death 
     FROM kingdom AS R1, dinasty AS D1, dinasty AS D2 
     WHERE R1.king=D1.name 
    ) AS R2 
    WHERE R1.death-R1.birth < R2.death-R2.birth 
); 

Lo que está dentro de la NO EN es correcta.

+1

No afecta su código, pero deletree la dinastía correctamente. –

Respuesta

18

que está proyectando tres columnas en la subconsulta, pero la comparación de una sola uno de ellos en la cláusula IN. Seleccionar sólo la columna requerida (r1.king) para la IN en la subconsulta:

SELECT kingdom.king, dinasty.birth, dinasty.death 
FROM kingdom, dinasty 
WHERE kingdom.king = dinasty.name AND kingdom.king NOT IN 
(
    SELECT DISTINCT R1.king 
    FROM 
    (
     SELECT DISTINCT R1.king, D1.birth, D1.death 
     FROM kingdom AS R1, dinasty AS D1, dinasty AS D2 
     WHERE R1.king=D1.name 
    ) AS R1, 
    (
     SELECT DISTINCT R1.king, D1.birth, D1.death 
     FROM kingdom AS R1, dinasty AS D1, dinasty AS D2 
     WHERE R1.king=D1.name 
    ) AS R2 
    WHERE R1.death-R1.birth < R2.death-R2.birth 
); 
+0

muchas gracias :) – Epi

+0

Además, si puede hacerlo, intente mover la subconsulta en la cláusula from (como una tabla derivada con un campo adecuado para unir), ya que será considerablemente más rápido, evaluando solo una vez, en lugar de una vez por fila – d11wtq

8

Como se ha contestado, el número de columnas no coincide, pero hay una manera mucho más sencilla de escribir esto.

Al escribir consultas, es mejor pensar en ellas por etapas. En primer lugar, es necesario saber la edad de cada rey era cuando murieron:

SELECT *, death-birth AS lived_for FROM dinasty 

Ahora que tiene eso, se puede utilizar ON DISTINCT para encontrar al rey de más larga vida de cada reino

SELECT DISTINCT ON(name) name, birth, death, lived_for 
    FROM (
     SELECT *, death-birth AS lived_for FROM dinasty 
    ) a 
    ORDER BY name, lived_for DESC 
; 

El distintivo on tomará la primera fila para cada valor distinto, por lo que es importante que lo vincule con el ORDER BY correcto. Primero ordenamos por el nombre de la dinastía, luego cuánto vivió el rey por en orden descendente. Eso significa que el primer rey que se muestra para cada dinastía será el más longevo, y ese es el registro que DISTINCT ON guardará para cada dinasty.

Tenga en cuenta que también me quita la unión a kindgom, pero se puede añadir que de nuevo si es necesario:

SELECT k.*, oldest.* 
    FROM (
    SELECT DISTINCT ON(name) name, birth, death, lived_for 
     FROM (
      SELECT *, death-birth AS lived_for FROM dinasty 
     ) a 
     ORDER BY name, lived_for DESC 
    ) oldest 
    JOIN kingdom k ON k.king = oldest.name 
; 

Por último, si alguna vez tiene que utilizar varias columnas en un sub-select, se puede utilizar la construcción ROW():

SELECT ... 
    FROM table_a 
    WHERE ROW(f1, f2, f3) NOT IN (SELECT f1a, f2a, f3a FROM ...) 
; 
+0

¿Por qué fue esto downvoted? –

+0

Buena pregunta; nada obviamente malo para mí, dejar un comentario en explicación habría sido cortés. –

+0

¡gracias por señalar la opción FILA! Resolvió mi problema (ligeramente diferente) :) – wmebane

Cuestiones relacionadas