PostgreSQL में, क्या पहला प्रकार सुरक्षित है () कुल फ़ंक्शन?


21

पूरा सवाल फिर से लिखना

मैं पहले () एग्रीगेट फंक्शन की तलाश में हूं।

यहाँ मुझे कुछ ऐसा मिला जो लगभग काम करता है:

CREATE OR REPLACE FUNCTION public.first_agg ( anyelement, anyelement )
RETURNS anyelement LANGUAGE sql IMMUTABLE STRICT AS $$
        SELECT $1;
$$;

-- And then wrap an aggregate around it
CREATE AGGREGATE public.first (
        sfunc    = public.first_agg,
        basetype = anyelement,
        stype    = anyelement
);

समस्या यह है कि जब एक varchar (n) कॉलम पहले () फ़ंक्शन से गुजरता है, तो इसे सरल varchar (एक आकार के बिना) में बदल दिया जाता है। किसी फ़ंक्शन को RETURNS SETOF एनीमेलमेंट के रूप में क्वेरी वापस करने की कोशिश कर रहा है, मुझे निम्नलिखित त्रुटि मिलती है:

त्रुटि: क्वेरी की संरचना फ़ंक्शन परिणाम प्रकार से मेल नहीं खाती है एस्टाडो डी एसक्यूएल: 42804 Detalhe: लौटा हुआ प्रकार चरित्र भिन्नता कॉलम में अपेक्षित प्रकार वर्ण भिन्नता (40) से मेल नहीं खाती है। संदर्भ: PL / pgSQL फ़ंक्शनrr_table_at_time (किसी भी समय के बिना टाइमस्टैम्प) ) RETURN QUERY पर लाइन 31

उसी विकी पृष्ठ में फ़ंक्शन के C संस्करण का लिंक होता है जो ऊपर की जगह लेगा। मुझे नहीं पता कि इसे कैसे स्थापित किया जाए, लेकिन मुझे आश्चर्य है कि अगर यह संस्करण मेरी समस्या को हल कर सकता है।

इस बीच, वहाँ एक तरीका है जिससे मैं उपरोक्त फ़ंक्शन को बदल सकता हूं ताकि यह उसी प्रकार के इनपुट कॉलम को वापस कर दे?

जवाबों:


18

DISTINCT ON()

बस एक साइड नोट के रूप में, यह ठीक है कि क्या DISTINCT ON()करता है (भ्रमित होने की नहीं DISTINCT)

SELECT DISTINCT ON ( expression [, ...] ) दी गई पंक्तियों के प्रत्येक सेट की केवल पहली पंक्ति है जहाँ दिए गए भाव समान हैंDISTINCT ONभाव के समान ही नियमों का उपयोग कर समझा जाता है ORDER BY(ऊपर देखें)। ध्यान दें कि प्रत्येक सेट की "पहली पंक्ति" अप्रत्याशित है जब तक ORDER BYयह सुनिश्चित करने के लिए उपयोग नहीं किया जाता है कि वांछित पंक्ति पहले दिखाई देती है। उदाहरण के लिए

इसलिए यदि आप लिखते हैं,

SELECT myFirstAgg(z)
FROM foo
GROUP BY x,y;

यह प्रभावी रूप से है

SELECT DISTINCT ON(x,y) z
FROM foo;
-- ORDER BY z;

इसमें वह प्रथम लेता है z। दो महत्वपूर्ण अंतर हैं,

  1. आप आगे एकत्रीकरण के बिना किसी भी कीमत पर अन्य कॉलम भी चुन सकते हैं

    SELECT DISTINCT ON(x,y) z, k, r, t, v
    FROM foo;
    -- ORDER BY z, k, r, t, v;
  2. क्योंकि कोई ऐसा नहीं है जिसके साथ GROUP BYआप (वास्तविक) समुच्चय का उपयोग नहीं कर सकते हैं

    CREATE TABLE foo AS
    SELECT * FROM ( VALUES
      (1,2,3),
      (1,2,4),
      (1,2,5)
    ) AS t(x,y,z);
    
    SELECT DISTINCT ON (x,y) z, sum(z)
    FROM foo;
    
    -- fails, as you should expect.
    SELECT DISTINCT ON (x,y) z, sum(z)
    FROM foo;
    
    -- would not otherwise fail.
    SELECT myFirstAgg(z), sum(z)
    FROM foo
    GROUP BY x,y;

मत भूलना ORDER BY

इसके अलावा, जब मैंने इसे बोल्ड नहीं किया तो मैं अब करूंगा

ध्यान दें कि प्रत्येक सेट की "पहली पंक्ति" अप्रत्याशित है जब तक कि वांछित पंक्ति पहले प्रकट न हो जाए यह सुनिश्चित करने के लिए ORDER BY का उपयोग किया जाता है। उदाहरण के लिए

हमेशा एक के ORDER BYसाथ उपयोग करेंDISTINCT ON

एक ऑर्डर-सेट एग्रिगेट फ़ंक्शन का उपयोग करना

मैं बहुत से लोगों को तलाश कर रहे हैं की कल्पना first_value, आदेश दिया सेट सकल कार्य । बस वहाँ से बाहर फेंकना चाहता था। यह इस तरह दिखेगा, यदि फ़ंक्शन मौजूद है:

SELECT a, b, first_value() WITHIN GROUP (ORDER BY z)    
FROM foo
GROUP BY a,b;

लेकिन, अफसोस आप ऐसा कर सकते हैं।

SELECT a, b, percentile_disc(0) WITHIN GROUP (ORDER BY z)   
FROM foo
GROUP BY a,b;

1
इस उत्तर के साथ समस्या यह है कि यह केवल तभी काम करता है जब आप अपनी चयनित सूची में एक समग्र चाहते हैं, जो प्रश्न द्वारा निहित नहीं है। उदाहरण के लिए यदि आप एक तालिका से चयन करना चाहते हैं और कई ऑर्डर किए गए पहले मान पाते हैं, DISTINCT ONतो इस मामले में काम नहीं करेंगे। यह एक समग्र कार्य नहीं है, आप वास्तव में डेटा को फ़िल्टर कर रहे हैं और इसलिए आप इसे केवल एक बार ही कर सकते हैं।
DB140141

6

हाँ, मैंने PostgreSQL 9.4+ में कुछ सुविधाओं का उपयोग करके आपके मामले का एक आसान तरीका ढूंढ लिया है

आइए इस उदाहरण को देखें:

select  (array_agg(val ORDER BY i))[1] as first_value_orderby_i,
    (array_agg(val ORDER BY i DESC))[1] as last_value_orderby_i,
    (array_agg(val))[1] as last_value_all,
    (array_agg(val))[array_length(array_agg(val),1)] as last_value_all
   FROM (
        SELECT i, random() as val
        FROM generate_series(1,100) s(i)
        ORDER BY random()
    ) tmp_tbl

मुझे उम्मीद है कि यह आपके मामले में आपकी मदद करेगा।


इस समाधान के साथ संभावना यह है कि यह DOMAINडेटा प्रकारों या अन्य छोटे अपवादों के साथ काम नहीं करता है। यह बहुत अधिक जटिल और समय लेने वाला है, पूरे डेटा सेट की एक सरणी का निर्माण करता है। सरल समाधान एक कस्टम एग्रीगेट बनाना होगा, लेकिन अभी तक मुझे इसके साथ भी आदर्श समाधान नहीं मिला है। विंडो फ़ंक्शंस भी खराब हैं, क्योंकि वे उसी तरह से उपयोग नहीं किए जा सकते हैं जैसे आप समुच्चय का उपयोग कर सकते हैं (फ़िल्टर बयानों के साथ, या CROSS JOIN LATERAL में)
AlexanderMP

5

आपके प्रश्न का सीधा उत्तर नहीं है, लेकिन आपको first_valueविंडो फ़ंक्शन का प्रयास करना चाहिए । यह इस तरह काम करता है:

CREATE TABLE test (
    id SERIAL NOT NULL PRIMARY KEY,
    cat TEXT,
    value VARCHAR(2)
    date TIMESTAMP WITH TIME ZONE

);

फिर, यदि आप प्रत्येक cat(श्रेणी) में पहला आइटम चाहते हैं, तो आप इस तरह क्वेरी करेंगे:

SELECT
    cat,
    first_value(date) OVER (PARTITION BY cat ORDER BY date)
FROM
    test;

या:

SELECT
    cat,
    first_value(date) OVER w
FROM
    test
WINDOW w AS (PARTITION BY cat ORDER BY date);

क्षमा करें, मुझे नहीं लगता कि यह मेरे उपयोग के मामले पर लागू होता है। First_value एक एकत्रीकरण फ़ंक्शन नहीं है, एक निश्चित सामान्य मूल्य (आपके उदाहरण बिल्ली) के साथ के सभी रिकॉर्ड दिखाते हैं जो कि कुछ आदेश (आपकी उदाहरण तिथि) के अनुसार पहले के रूप में मूल्यांकन किया जाता है। मेरी जरूरत अलग है। मुझे पहली बार अशक्त मान का चयन करके, एक ही चयन में, कई स्तंभों को एकत्र करने की आवश्यकता है। यही है, यह ग्रुप बीवाई में प्रत्येक मूल्य संयोजन के लिए एक एकल रिकॉर्ड का उत्पादन करना चाहिए।
अलेक्जेंड्रे नेटो

2
उपरोक्त मिश्रण में अलग फेंककर काम करने के लिए बनाया जा सकता है select distinct x, first_value(y) over (partition by x), first_value(z) over (partition by x) from ...:। शायद अक्षम है, लेकिन मेरे लिए प्रोटोटाइप के साथ प्राप्त करने के लिए पर्याप्त है। हालांकि निश्चित रूप से कुछ फिर से आना!
मैक्स मर्फी
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.