sqlite2: Se une a los valores máximos por columna de otra tabla (referencia subconsulta)?
Pregunta
Estoy utilizando la siguiente base de datos:
CREATE TABLE datas (d_id INTEGER PRIMARY KEY, name_id numeric, countdata numeric);
INSERT INTO datas VALUES(1,1,20); //(NULL,1,20);
INSERT INTO datas VALUES(2,1,47); //(NULL,1,47);
INSERT INTO datas VALUES(3,2,36); //(NULL,2,36);
INSERT INTO datas VALUES(4,2,58); //(NULL,2,58);
INSERT INTO datas VALUES(5,2,87); //(NULL,2,87);
CREATE TABLE names (n_id INTEGER PRIMARY KEY, name text);
INSERT INTO names VALUES(1,'nameA'); //(NULL,'nameA');
INSERT INTO names VALUES(2,'nameB'); //(NULL,'nameB');
Lo que me gustaría hacer, es seleccionar todos los valores (filas) de names
- a la que se añadirán todas las columnas de datas
, para la fila donde datas
.countdata
es máxima para n_id
(y, por supuesto, donde name_id = n_id
) .
Me algo puede llegar con la siguiente consulta:
sqlite> .header ON
sqlite> SELECT * FROM names AS n1
LEFT OUTER JOIN (
SELECT d_id, name_id, countdata FROM datas AS d1
WHERE d1.countdata IN (
SELECT MAX(countdata) FROM datas
WHERE name_id=1
)
) AS p1 ON n_id=name_id;
n1.n_id|n1.name|p1.d_id|p1.name_id|p1.countdata
1|nameA|2|1|47
2|nameB|||
Sin embargo ... - obviamente -. Sólo funciona para una sola fila (el que está establecido explícitamente por name_id=1
)
El problema es que la consulta SQL falla cada vez que intento hacer referencia alguna manera el n_id
"actual":
sqlite> SELECT * FROM names AS n1
LEFT OUTER JOIN (
SELECT d_id, name_id, countdata FROM datas AS d1
WHERE d1.countdata IN (
SELECT MAX(countdata) FROM datas
WHERE name_id=n1.n_id
)
) AS p1 ON n_id=name_id;
SQL error: no such column: n1.n_id
¿Hay alguna manera de lograr lo que quiero en SQLite2 ??
Gracias de antemano,
Saludos!
Solución
Oh, bueno - que no era trivial en absoluto, pero aquí hay una solución:
sqlite> SELECT * FROM names AS n1
LEFT OUTER JOIN (
SELECT d1.*
FROM datas AS d1, (
SELECT max(countdata) as countdata,name_id
FROM datas
GROUP BY name_id
) AS ttemp
WHERE d1.name_id = ttemp.name_id AND d1.countdata = ttemp.countdata
) AS p1 ON n1.n_id=p1.name_id;
n1.n n1.name p1.d_id p1.name_id p1.countdata
---- ------------ ---------- ---------- -----------------------------------
1 nameA 2 1 47
2 nameB 5 2 87
Bueno, espero que esto termina ayudando a alguien, :) Saludos!
Notas : Tenga en cuenta que sólo llamar Max (countdata) mete la pata d_id
competely:
sqlite> select d_id,name_id,max(countdata) as countdata from datas group by name_id;
d_id name_id countdata
---- ------------ ----------
3 2 87
1 1 47
así que para obtener correcta d_id
correspondiente, tenemos que hacer max()
en datas
separado - y luego realizar una especie de una intersección con la datas
completa ( excepto que se cruzan en SQLite requiere que haya el mismo número de columnas en ambos conjuntos de datos, lo cual no es el caso aquí - y aunque lo hizo de esa manera, como se ha visto anteriormente d_id
será un error, por lo que se cruzan no funcionará ).
Una forma de hacerlo es en el uso de un tipo de una tabla temporal, y luego utilizar una tabla de selección múltiple en consulta con el fin de establecer condiciones de plena entre datas
y el subconjunto devuelto a través de max(countdata)
, como se muestra a continuación:
sqlite> CREATE TABLE ttemp AS SELECT max(countdata) as countdata,name_id FROM datas GROUP BY name_id;
sqlite> SELECT d1.*, ttemp.* FROM datas AS d1, ttemp WHERE d1.name_id = ttemp.name_id AND d1.countdata = ttemp.countdata;
d1.d d1.name_id d1.countda ttemp.coun ttemp.name_id
---- ------------ ---------- ---------- -----------------------------------
2 1 47 47 1
5 2 87 87 2
sqlite> DROP TABLE ttemp;
o, podemos reescribir lo anterior por lo que un sub consulta SELECT se utiliza, como este (sub-select?):
sqlite> SELECT d1.* FROM datas AS d1, (SELECT max(countdata) as countdata,name_id FROM datas GROUP BY name_id) AS ttemp WHERE d1.name_id = ttemp.name_id AND d1.countdata = ttemp.countdata;
d1.d d1.name_id d1.countda
---- ------------ ----------
2 1 47
5 2 87