Estoy tratando de escribir la siguiente consulta en postgresql:
select name, author_id, count(1),
(select count(1)
from names as n2
where n2.id = n1.id
and t2.author_id = t1.author_id
)
from names as n1
group by name, author_id
Esto sin duda funcionaría en Microsoft SQL Server, pero no en postegresql. Leí un poco su documentación y parece que podría reescribirlo como:
select name, author_id, count(1), total
from names as n1, (select count(1) as total
from names as n2
where n2.id = n1.id
and n2.author_id = t1.author_id
) as total
group by name, author_id
Pero eso devuelve el siguiente error en postegresql: "la subconsulta en FROM no puede referirse a otras relaciones del mismo nivel de consulta". Entonces estoy estancado. ¿Alguien sabe cómo puedo lograr eso?
Gracias
sql
sql-server
postgresql
subquery
Ricardo
fuente
fuente
Respuestas:
No estoy seguro de entender perfectamente tu intención, pero quizás lo siguiente se acerque a lo que quieres:
select n1.name, n1.author_id, count_1, total_count from (select id, name, author_id, count(1) as count_1 from names group by id, name, author_id) n1 inner join (select id, author_id, count(1) as total_count from names group by id, author_id) n2 on (n2.id = n1.id and n2.author_id = n1.author_id)
Desafortunadamente, esto agrega el requisito de agrupar la primera subconsulta por id, así como por nombre y author_id, que no creo que se quisiera. Sin embargo, no estoy seguro de cómo solucionarlo, ya que necesita tener una identificación disponible para unirse a la segunda subconsulta. Quizás a alguien más se le ocurra una solución mejor.
Comparte y Disfruta.
fuente
Como complemento de @Bob Jarvis y @dmikam responden, Postgres no realiza un buen plan cuando no usa LATERAL, debajo de una simulación, en ambos casos los resultados de los datos de consulta son los mismos, pero el costo es muy diferente
Estructura de la mesa
CREATE TABLE ITEMS ( N INTEGER NOT NULL, S TEXT NOT NULL ); INSERT INTO ITEMS SELECT (random()*1000000)::integer AS n, md5(random()::text) AS s FROM generate_series(1,1000000); CREATE INDEX N_INDEX ON ITEMS(N);
Realización
JOIN
conGROUP BY
en subconsulta sinLATERAL
EXPLAIN SELECT I.* FROM ITEMS I INNER JOIN ( SELECT COUNT(1), n FROM ITEMS GROUP BY N ) I2 ON I2.N = I.N WHERE I.N IN (243477, 997947);
Los resultados
Merge Join (cost=0.87..637500.40 rows=23 width=37) Merge Cond: (i.n = items.n) -> Index Scan using n_index on items i (cost=0.43..101.28 rows=23 width=37) Index Cond: (n = ANY ('{243477,997947}'::integer[])) -> GroupAggregate (cost=0.43..626631.11 rows=861418 width=12) Group Key: items.n -> Index Only Scan using n_index on items (cost=0.43..593016.93 rows=10000000 width=4)
Utilizando
LATERAL
EXPLAIN SELECT I.* FROM ITEMS I INNER JOIN LATERAL ( SELECT COUNT(1), n FROM ITEMS WHERE N = I.N GROUP BY N ) I2 ON 1=1 --I2.N = I.N WHERE I.N IN (243477, 997947);
Resultados
Mi versión de Postgres es
PostgreSQL 10.3 (Debian 10.3-1.pgdg90+1)
fuente
Solo estoy respondiendo aquí con la versión formateada del sql final que necesitaba según la respuesta de Bob Jarvis como se publicó en mi comentario anterior:
select n1.name, n1.author_id, cast(count_1 as numeric)/total_count from (select id, name, author_id, count(1) as count_1 from names group by id, name, author_id) n1 inner join (select author_id, count(1) as total_count from names group by author_id) n2 on (n2.author_id = n1.author_id)
fuente
Sé que esto es antiguo, pero desde Postgresql 9.3 hay una opción para usar una palabra clave "LATERAL" para usar subconsultas RELACIONADAS dentro de JOINS, por lo que la consulta de la pregunta se vería así:
SELECT name, author_id, count(*), t.total FROM names as n1 INNER JOIN LATERAL ( SELECT count(*) as total FROM names as n2 WHERE n2.id = n1.id AND n2.author_id = n1.author_id ) as t ON 1=1 GROUP BY n1.name, n1.author_id
fuente
select n1.name, n1.author_id, cast(count_1 as numeric)/total_count from (select id, name, author_id, count(1) as count_1 from names group by id, name, author_id) n1 inner join (select distinct(author_id), count(1) as total_count from names) n2 on (n2.author_id = n1.author_id) Where true
se usa
distinct
si hay más unión interna, porque el rendimiento de un grupo de unión más es lentofuente