PostgreSQL में एक फ़ंक्शन के अंदर चयन का परिणाम कैसे लौटाएं?


106

मेरा यह कार्य PostgreSQL में है, लेकिन मुझे नहीं पता कि क्वेरी का परिणाम कैसे लौटाया जाए:

CREATE OR REPLACE FUNCTION wordFrequency(maxTokens INTEGER)
  RETURNS SETOF RECORD AS
$$
BEGIN
    SELECT text, count(*), 100 / maxTokens * count(*)
    FROM (
        SELECT text
    FROM token
    WHERE chartype = 'ALPHABETIC'
    LIMIT maxTokens
    ) as tokens
    GROUP BY text
    ORDER BY count DESC
END
$$
LANGUAGE plpgsql;

लेकिन मुझे नहीं पता कि PostgreSQL फ़ंक्शन के अंदर क्वेरी का परिणाम कैसे लौटाया जाए।

मैंने पाया कि वापसी का प्रकार SETOF RECORDसही होना चाहिए ? लेकिन रिटर्न कमांड सही नहीं है।

ऐसा करने का सही तरीका क्या है?


आप उनकी गिनती क्यों करते हैं; क्या आपके टोकन टोकन में डुप्लिकेट टोकन हैं? इसके अलावा: कृपया अपने प्रश्न में तालिका की परिभाषा जोड़ें।
Wildplasser 15

1
क्या यह आपका पूरा कार्य है? यदि आपके पास फ़ंक्शन में कोई अन्य कथन नहीं है, तो आपको इसे बनाना चाहिए LANGUAGE SQL
jpmc26

जवाबों:


134

उपयोग करें RETURN QUERY:

CREATE OR REPLACE FUNCTION word_frequency(_max_tokens int)
  RETURNS TABLE (txt   text   -- also visible as OUT parameter inside function
               , cnt   bigint
               , ratio bigint) AS
$func$
BEGIN
   RETURN QUERY
   SELECT t.txt
        , count(*) AS cnt                 -- column alias only visible inside
        , (count(*) * 100) / _max_tokens  -- I added brackets
   FROM  (
      SELECT t.txt
      FROM   token t
      WHERE  t.chartype = 'ALPHABETIC'
      LIMIT  _max_tokens
      ) t
   GROUP  BY t.txt
   ORDER  BY cnt DESC;                    -- potential ambiguity 
END
$func$  LANGUAGE plpgsql;

कॉल करें:

SELECT * FROM word_frequency(123);

स्पष्टीकरण:

  • यह है बहुत स्पष्ट रूप से बस रिकॉर्ड के रूप में यह घोषित करने से वापसी प्रकार परिभाषित करने के लिए और अधिक व्यावहारिक। इस तरह आपको हर फ़ंक्शन कॉल के साथ एक कॉलम परिभाषा सूची प्रदान करने की आवश्यकता नहीं है। RETURNS TABLEऐसा करने का एक तरीका है। और भी हैं। डेटा प्रकार के OUTमापदंडों को ठीक उसी तरह से मेल खाना है जो क्वेरी द्वारा वापस किया गया है।

  • OUTमापदंडों के लिए नामों को सावधानी से चुनें । वे लगभग कहीं भी फ़ंक्शन बॉडी में दिखाई देते हैं। झगड़े या अप्रत्याशित परिणामों से बचने के लिए तालिका-समान नाम के कॉलम। मैंने अपने उदाहरण में सभी कॉलमों के लिए किया।

    लेकिन पैरामीटर और उसी नाम के कॉलम उर्फ ​​के बीच संभावित नामकरण संघर्ष पर ध्यान दें । इस विशेष मामले में ( ) Postgres पैरामीटर के ऊपर कॉलम एलियास का उपयोग करता है । यह अन्य संदर्भों में अस्पष्ट हो सकता है, हालांकि। किसी भी भ्रम से बचने के विभिन्न तरीके हैं:OUTcntRETURN QUERY SELECT ...OUT

    1. चयन सूची में आइटम की क्रमिक स्थिति का उपयोग करें ORDER BY 2 DESC:। उदाहरण:
    2. अभिव्यक्ति को दोहराएं ORDER BY count(*)
    3. (यहां लागू नहीं है।) कॉन्फ़िगरेशन पैरामीटर सेट करें plpgsql.variable_conflictया #variable_conflict error | use_variable | use_columnफ़ंक्शन में विशेष कमांड का उपयोग करें । देख:
  • कॉलम नामों के रूप में "टेक्स्ट" या "काउंट" का उपयोग न करें। दोनों Postgres में उपयोग करने के लिए कानूनी हैं, लेकिन "गणना" मानक SQL में एक आरक्षित शब्द है और एक बुनियादी फ़ंक्शन नाम और "टेक्स्ट" एक बुनियादी डेटा प्रकार है। भ्रामक त्रुटियां हो सकती हैं। मैं अपने उदाहरणों में उपयोग करता हूं txtऔर करता cntहूं।

  • ;हेडर में एक लापता और एक वाक्यविन्यास त्रुटि को जोड़ा गया । (_max_tokens int), नहीं (int maxTokens)- नाम के बाद टाइप करें

  • पूर्णांक विभाजन के साथ काम करते समय, पहले वाली को गुणा करना और बाद में विभाजित करना, गोल त्रुटि को कम करने के लिए बेहतर है। इससे भी बेहतर: साथ काम numeric(या एक अस्थायी बिंदु प्रकार)। निचे देखो।

विकल्प

यह वही है जो मुझे लगता है कि आपकी क्वेरी वास्तव में दिखनी चाहिए ( प्रति टोकन एक रिश्तेदार शेयर की गणना ):

CREATE OR REPLACE FUNCTION word_frequency(_max_tokens int)
  RETURNS TABLE (txt            text
               , abs_cnt        bigint
               , relative_share numeric) AS
$func$
BEGIN
   RETURN QUERY
   SELECT t.txt, t.cnt
        , round((t.cnt * 100) / (sum(t.cnt) OVER ()), 2)  -- AS relative_share
   FROM  (
      SELECT t.txt, count(*) AS cnt
      FROM   token t
      WHERE  t.chartype = 'ALPHABETIC'
      GROUP  BY t.txt
      ORDER  BY cnt DESC
      LIMIT  _max_tokens
      ) t
   ORDER  BY t.cnt DESC;
END
$func$  LANGUAGE plpgsql;

अभिव्यक्ति sum(t.cnt) OVER ()एक विंडो फ़ंक्शन है । आप सब- वेरी के बजाय एक सीटीई का उपयोग कर सकते हैं - सुंदर, लेकिन एक उपक्वरी आम तौर पर इस तरह के सरल मामलों में सस्ता है।

मापदंडों के साथ काम करते समय या (जो मापदंडों का निहित उपयोग करता है ) एक अंतिम स्पष्ट RETURNकथन की आवश्यकता नहीं है (लेकिन अनुमति दी गई है )।OUTRETURNS TABLEOUT

round()दो मापदंडों के साथ केवल numericप्रकारों के लिए काम करता है । count()उपनगर में एक bigintपरिणाम उत्पन्न होता है और sum()इस पर bigintएक numericपरिणाम उत्पन्न होता है, इस प्रकार हम एक numericसंख्या के साथ स्वचालित रूप से व्यवहार करते हैं और सब कुछ बस जगह में गिर जाता है।


आपके उत्तर और सुधार के लिए बहुत धन्यवाद। अब ठीक काम कर रहा है (मैंने केवल अनुपात प्रकार को संख्यात्मक में बदल दिया है)।
रेनाटो दिनानी

@ RenatoDinhaniConceição कूल! मैंने एक ऐसा संस्करण जोड़ा है जो आपके द्वारा पूछे गए अतिरिक्त प्रश्न का उत्तर दे भी सकता है और नहीं भी। ;)
इरविन ब्रान्डस्टेट्टर

अच्छा, एक ही बात है मुझे लगता है कि आपको RETURN;इससे पहले एक चीज की जरूरत है END;, कम से कम मैंने किया - लेकिन मैं एक यूनिअन कर रहा हूं इसलिए मुझे यकीन नहीं है कि अगर यह अलग है।
यक्ष

@yekta: मैंने भूमिका के विषय में कुछ जानकारी जोड़ी RETURN। एक असंबंधित त्रुटि को ठीक किया और उस पर रहते हुए कुछ सुधार जोड़े।
इरविन ब्रान्डसेट्टर

1
ऐसा करने का तरीका क्या है जब आप रिटर्न टेबल () में बाधा नहीं डालना चाहते हैं। IE रिटर्न्स टेबल (*)?
Nick

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