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

সমস্যাটি হ'ল যখন কোনও ভার্চার (এন) কলামটি প্রথম () ফাংশনটির মধ্য দিয়ে যায়, তখন এটি সরল বর্ণচর্চায় (কোনও আকার ছাড়াই) রূপান্তরিত হয়। কোনও ফাংশনে ক্যোয়ারীটি SETOF প্রত্যাহার হিসাবে ফেরত দেওয়ার চেষ্টা করছি, আমি নিম্নলিখিত ত্রুটিটি পেয়েছি:

ত্রুটি: ক্যোয়ারির কাঠামো ফাংশন ফলাফলের ধরণের সাথে মেলে না এস্টাদো ডি এসকিউএল: 42804 বিবরণ: প্রত্যাবর্তিত প্রকারের অক্ষরটি কলাম 2-তে প্রত্যাশিত প্রকারের চরিত্রের সাথে মেলে না (প্রবন্ধ): প্রবন্ধ: পিএল / পিজিএসকিউএল ফাংশন vsr_table_at_time (যে কোনও সময়, টাইমস্ট্যাম্প ছাড়াই টাইমস্ট্যাম্প) ) রিটার্ন QUERY এ 31 লাইন

একই উইকির পৃষ্ঠায় ফাংশনের সি সংস্করণের লিঙ্ক রয়েছে যা উপরেরটি প্রতিস্থাপন করবে। আমি এটি ইনস্টল করতে জানি না, তবে আমি ভাবছি যে এই সংস্করণটি আমার সমস্যার সমাধান করতে পারে।

এদিকে, আমি কি কোনও উপায়ে উপরের ফাংশনটি পরিবর্তন করতে পারি যাতে এটি ঠিক একই ধরণের ইনপুট কলামটি দেয়?

উত্তর:


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সঙ্গে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

হ্যাঁ, পোস্টগ্র্রেএসকিউএল 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ডেটা ধরণের বা অন্য ছোট ব্যতিক্রমগুলির সাথে কাজ করে না । এটি আরও অনেক জটিল এবং সময়সাপেক্ষ, পুরো ডেটা সেটের একটি অ্যারে তৈরি করে। সহজ সমাধানটি হ'ল একটি কাস্টম সমষ্টি তৈরি করা হবে, তবে এখনও পর্যন্ত আমি আদর্শ সমাধানটি খুঁজে পেলাম না। উইন্ডো ফাংশনগুলিও খারাপ, যেহেতু আপনি সমষ্টিগুলি ব্যবহার করতে পারেন ঠিক তেমনভাবে সেগুলি ব্যবহার করা যায় না (ফিল্টার স্টেটমেন্ট সহ, বা ক্রস যোগসূত্রে)
আলেকজান্ডার

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

দুঃখিত, আমি মনে করি না এটি আমার ব্যবহারের ক্ষেত্রে প্রযোজ্য। ফার্স্ট_ভ্যালু কোনও একীকরণের ক্রিয়াকলাপ নয়, একটি নির্দিষ্ট সাধারণ মান (আপনার উদাহরণস্বরূপ বিড়াল) সহ সমস্ত রেকর্ড দেখায় যা কিছু আদেশ অনুসারে প্রথম হিসাবে মূল্যায়ন করা হয় (আপনার উদাহরণের তারিখ)। আমার চাহিদা অন্যরকম। আমাকে একই নির্বাচনের মধ্যে প্রথম নাল মানটি বেছে নিয়ে কয়েকটি কলাম একত্রিত করতে হবে। এটি হ'ল, গ্রুপের মাধ্যমে প্রতিটি মান সংমিশ্রণের জন্য এটি একক রেকর্ড আউটপুট করা উচিত।
আলেকজান্দ্রে

2
উপরে মিশ্রণ মধ্যে স্বতন্ত্র ছুঁড়ে কাজ করার জন্য তৈরি করা যেতে পারে: select distinct x, first_value(y) over (partition by x), first_value(z) over (partition by x) from ...। সম্ভবত অদক্ষ তবে প্রোটোটাইপিংয়ের জন্য আমার পক্ষে যথেষ্ট। অবশ্যই আবার দেখার জন্য কিছু!
ম্যাক্স মার্ফি
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.