tutorial registros español entre ejemplos diferencias contar and mysql sql sqlite sqlite3

registros - ¿Por qué los resultados de SELECT difieren entre mysql y sqlite?



rowcount php (3)

Estoy volviendo a hacer esta question de una manera simplificada y ampliada.

Considere estas declaraciones SQL:

create table foo (id INT, score INT); insert into foo values (106, 4); insert into foo values (107, 3); insert into foo values (106, 5); insert into foo values (107, 5); select T1.id, avg(T1.score) avg1 from foo T1 group by T1.id having not exists ( select T2.id, avg(T2.score) avg2 from foo T2 group by T2.id having avg2 > avg1);

Usando sqlite, la instrucción select devuelve:

id avg1 ---------- ---------- 106 4.5 107 4.0

y mysql devuelve:

+------+--------+ | id | avg1 | +------+--------+ | 106 | 4.5000 | +------+--------+

Por lo que puedo decir, los resultados de mysql son correctos y los de sqlite son incorrectos. Intenté convertir en real con sqlite como se muestra a continuación, pero devuelve dos registros aún:

select T1.id, cast(avg(cast(T1.score as real)) as real) avg1 from foo T1 group by T1.id having not exists ( select T2.id, cast(avg(cast(T2.score as real)) as real) avg2 from foo T2 group by T2.id having avg2 > avg1);

¿Por qué sqlite devuelve dos registros?

Actualización rápida :

Ejecuté la declaración contra la última versión de sqlite (3.7.11) y aún obtengo dos registros.

Otra actualización :

Envié un correo electrónico a [email protected] sobre el problema.

Yo mismo, he estado jugando con VDBE y encontré algo interesante. Dividí la traza de ejecución de cada bucle que not exists (una para cada grupo promedio).

Para tener tres grupos promedio, usé las siguientes afirmaciones:

create table foo (id VARCHAR(1), score INT); insert into foo values (''c'', 1.5); insert into foo values (''b'', 5.0); insert into foo values (''a'', 4.0); insert into foo values (''a'', 5.0); PRAGMA vdbe_listing = 1; PRAGMA vdbe_trace=ON; select avg(score) avg1 from foo group by id having not exists ( select avg(T2.score) avg2 from foo T2 group by T2.id having avg2 > avg1);

Vemos claramente que de alguna manera lo que debería ser r:4.5 ha convertido en i:5 :

Ahora estoy tratando de ver por qué es eso.

Edición final :

Así que he estado jugando lo suficiente con el código fuente de sqlite. Ahora entiendo a la bestia mucho mejor, aunque dejaré que el desarrollador original lo resuelva ya que parece que ya lo está haciendo:

http://www.sqlite.org/src/info/430bb59d79

Curiosamente, al menos para mí, parece que las versiones más nuevas (algunas veces después de la versión que estoy usando) admiten la inserción de múltiples registros como se usa en un caso de prueba agregado en el compromiso mencionado anteriormente:

CREATE TABLE t34(x,y); INSERT INTO t34 VALUES(106,4), (107,3), (106,5), (107,5);


¿Has probado esta versión? :

select T1.id, avg(T1.score) avg1 from foo T1 group by T1.id having not exists ( select T2.id, avg(T2.score) avg2 from foo T2 group by T2.id having avg(T2.score) > avg(T1.score));

También este (que debería estar dando los mismos resultados):

select T1.* from ( select id, avg(score) avg1 from foo group by id ) T1 where not exists ( select T2.id, avg(T2.score) avg2 from foo T2 group by T2.id having avg(T2.score) > avg1);

La consulta también se puede manejar con tablas derivadas, en lugar de subconsultas en la cláusula HAVING :

select ta.id, ta.avg1 from ( select id, avg(score) avg1 from foo group by id ) ta JOIN ( select avg(score) avg1 from foo group by id order by avg1 DESC LIMIT 1 ) tmp ON tmp.avg1 = ta.avg1


Intenté meterme con algunas variantes de consulta.

Parece que, como sqlite tiene errores en el uso de campos declarados anteriores en expresiones HAVING anidadas.

En tu ejemplo, avg1 en segundo lugar es siempre igual a 5.0

Mira:

select T1.id, avg(T1.score) avg1 from foo T1 group by T1.id having not exists ( SELECT 1 AS col1 GROUP BY col1 HAVING avg1 = 5.0);

Este no devuelve nada, pero la ejecución de la siguiente consulta devuelve ambos registros:

... having not exists ( SELECT 1 AS col1 GROUP BY col1 HAVING avg1 <> 5.0);

No puedo encontrar ningún error similar en la lista de tickets de sqlite .


Veamos estas dos formas, usaré postgres 9.0 como mi base de datos de referencia

(1)

-- select rows from foo select T1.id, avg(T1.score) avg1 from foo T1 group by T1.id -- where we don''t have any rows from T2 having not exists ( -- select rows from foo select T2.id, avg(T2.score) avg2 from foo T2 group by T2.id -- where the average score for any row is greater than the average for -- any row in T1 having avg2 > avg1); id | avg1 -----+-------------------- 106 | 4.5000000000000000 (1 row)

luego movamos parte de la lógica dentro de la subconsulta, deshaciéndonos del ''no'': (2)

-- select rows from foo select T1.id, avg(T1.score) avg1 from foo T1 group by T1.id -- where we do have rows from T2 having exists ( -- select rows from foo select T2.id, avg(T2.score) avg2 from foo T2 group by T2.id -- where the average score is less than or equal than the average for any row in T1 having avg2 <= avg1); -- I think this expression will be true for all rows as we are in effect doing a --cartesian join -- with the ''having'' only we don''t display the cartesian row set id | avg1 -----+-------------------- 106 | 4.5000000000000000 107 | 4.0000000000000000 (2 rows)

así que debes preguntarte: ¿qué quieres decir realmente cuando haces esta subconsulta correlacionada dentro de una cláusula de haber, si evalúa cada fila contra cada fila de la consulta principal, estamos haciendo una unión cartesiana y no creo que Debería estar apuntando los dedos al motor SQL.

si desea que cada fila sea inferior al promedio máximo, lo que debería decir es:

select T1.id, avg(T1.score) avg1 from foo T1 group by T1.id having avg1 not in (select max(avg1) from (select id,avg(score) avg1 from foo group by id))