SQL सर्वर जैसे क्लॉज से जुड़ने के साथ चुनिंदा क्लॉज में पोस्टग्रैक्कल सबक्विरी कैसे करें?


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 सर्वर पर काम करेगा, लेकिन यह 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 में उपशमन उसी क्वेरी स्तर के अन्य संबंधों को संदर्भित नहीं कर सकता है"। इसलिए मैं फंस गया हूं। क्या किसी को पता है कि मैं इसे कैसे हासिल कर सकता हूं?

धन्यवाद


वास्तव में ऐसा लगता है कि यह Postgres पर काम करना चाहिए (शायद 6 साल पहले यह :) नहीं था)
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 के साथ जुड़ने की जरूरत नहीं है, बस author_id। तो अंतिम प्रश्न यह है: n1.name, n1.author_id, count_1, total_count से (select id, name, author_id, count (1) के रूप में count_1 के रूप में id समूह से नाम, नाम, author_id, n1 इनर जॉइन (चयन author_id, का चयन करें) count (1) as_count as name_count by names_id द्वारा author_id) n2 on (n2.author_id = n1.author_id) अब मेरे पास यह है, कि मैं वास्तव में क्या चाहता हूं कि count_ount को divide_ करके एक सामान्यीकृत आवृत्ति बना दिया जाए। = D
रिकार्डो

ऑप्स, बस एहसास हुआ कि sql यहाँ ठीक से स्वरूपित नहीं होता है। :( पूरक का जवाब देंगे।
रिकार्डो

मुझे समस्या नहीं थी रिकैडो बात कर रहा था 'लेकिन इस एसक्यूएल ने मेरी समस्याओं को पूरी तरह से ठीक कर दिया ...: धन्यवाद!
tftd

16

पूरक @Bob जार्विस और @dmikam जवाब है, Postgres एक अच्छी योजना प्रदर्शन नहीं आप पार्श्व का उपयोग नहीं करते हैं, एक सिमुलेशन नीचे, दोनों ही मामलों क्वेरी डेटा परिणाम एक ही हैं, लेकिन लागत बहुत अलग हैं

तालिका संरचना

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

बिना सबकुछ के JOINसाथ प्रदर्शन करनाGROUP BYLATERAL

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)

मेरा पोस्टग्रेज संस्करण है PostgreSQL 10.3 (Debian 10.3-1.pgdg90+1)


3
LATERAL का उपयोग करने के संकेत के लिए धन्यवाद !!
तिल

14

मुझे पता है कि यह पुराना है, लेकिन Postgresql 9.3 के बाद से JOINS के अंदर संबंधित उप-वर्गों का उपयोग करने के लिए एक कीवर्ड "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
मुझे आश्चर्य है कि अगर इन दोनों प्रश्नों के प्रदर्शन में अंतर है, या यदि पोस्टग्रैक्स्ल के लिए यह एक ही योजना है
deFreitas

1
मैंने यह परीक्षण किया और इसका उत्तर यहाँ (मेरा उत्तर) है
deFreitas

13

मैं यहाँ पर केवल अपनी टिप्पणी में पोस्ट किए गए बॉब जार्विस उत्तर पर आधारित अंतिम एसक्यूएल के प्रारूपित संस्करण के साथ जवाब दे रहा हूं:

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अधिक आंतरिक जुड़ने पर उपयोग किया जाता है , क्योंकि अधिक समूह में शामिल होने का प्रदर्शन धीमा है

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.