SQL Server와 같은 절에서 조인을 사용하여 select 절에서 Postgresql 하위 쿼리를 수행하는 방법은 무엇입니까?


83

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

이것은 확실히 Microsoft SQL Server에서 작동하지만 postegresql에서는 전혀 작동하지 않습니다. 나는 그 문서를 조금 읽었고 그것을 다음과 같이 다시 쓸 수있을 것 같다 :

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

그러나 postegresql에 다음과 같은 오류를 반환합니다. "FROM의 하위 쿼리는 동일한 쿼리 수준의 다른 관계를 참조 할 수 없습니다." 그래서 나는 붙어 있습니다. 내가 어떻게 이룰 수 있는지 아는 사람 있나요?

감사


사실은 (는 :)하지 않았다 어쩌면 육년 전) 포스트 그레스에서 작동해야이 보인다
qwertzguy

답변:


124

귀하의 의도를 완벽하게 이해하고 있는지는 모르겠지만 다음과 같은 내용이 귀하가 원하는 것에 가깝습니다.

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)

불행히도 이것은 첫 번째 하위 쿼리를 id, name 및 author_id별로 그룹화해야한다는 요구 사항을 추가합니다. 두 번째 하위 쿼리에 가입 할 수있는 ID가 있어야하므로이 문제를 해결하는 방법을 모르겠습니다. 아마도 다른 누군가가 더 나은 해결책을 제시 할 것입니다.

공유하고 즐기십시오.


정말 효과가있는 완벽한 밥. 감사합니다! id와의 조인이 필요하지 않고 author_id 만 필요하기 때문에 약간 변경해야했습니다. 따라서 최종 쿼리는 다음과 같습니다. select n1.name, n1.author_id, count_1, total_count from (select id, name, author_id, count (1) as 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) 이제 제가 이것을 가지고 있으므로, 제가 정말로 원하는 것은 count_1을 total_count로 나누어 정규화 된 빈도를 갖는 것입니다. = D
Ricardo

ops, 방금 SQL이 여기에서 올바르게 형식화되지 않는다는 것을 깨달았습니다. :( 보완에 대한 답변을 제공합니다.
Ricardo

나는 Ricado가 말하는 문제가 없었지만이 SQL은 내 문제를 완전히 해결했습니다 ... : D 감사합니다 !!!
tftd 2011 년

16

@Bob Jarvis@dmikam 답변을 보완 하면 Postgres는 시뮬레이션 아래에서 LATERAL을 사용하지 않을 때 좋은 계획을 수행하지 못합니다. 두 경우 모두 쿼리 데이터 결과는 동일하지만 비용은 매우 다릅니다

테이블 구조

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);

수행 JOINGROUP BY하위 쿼리에서하지 않고LATERAL

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);

결과

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)

사용 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);

결과

Nested Loop  (cost=9.49..1319.97 rows=276 width=37)
  ->  Bitmap Heap Scan on items i  (cost=9.06..100.20 rows=23 width=37)
        Recheck Cond: (n = ANY ('{243477,997947}'::integer[]))
        ->  Bitmap Index Scan on n_index  (cost=0.00..9.05 rows=23 width=0)
              Index Cond: (n = ANY ('{243477,997947}'::integer[]))
  ->  GroupAggregate  (cost=0.43..52.79 rows=12 width=12)
        Group Key: items.n
        ->  Index Only Scan using n_index on items  (cost=0.43..52.64 rows=12 width=4)
              Index Cond: (n = i.n)

내 Postgres 버전은 PostgreSQL 10.3 (Debian 10.3-1.pgdg90+1)


3
LATERAL 사용에 대한 힌트에 감사드립니다 !!
leole

14

나는 이것이 오래 되었다는 것을 알고 있지만 Postgresql 9.3 부터 JOINS 내에서 RELATED 하위 쿼리를 사용하기 위해 키워드 "LATERAL"을 사용하는 옵션이 있으므로 질문의 쿼리는 다음과 같습니다.

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

1
이 두 쿼리의 성능이 다른지 또는 postgresql의 경우 동일한 계획
인지 궁금합니다

1
나는이 테스트를했고, 대답은 여기에 (내 대답)입니다
deFreitas

13

위의 의견에 게시 된대로 Bob Jarvis 답변을 기반으로 필요한 최종 SQL의 형식화 된 버전으로 여기에 대답하고 있습니다.

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)

2
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

distinct더 많은 조인 그룹 성능이 느리기 때문에 더 많은 내부 조인 인 경우 사용 됩니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.