পোস্টগ্রিজ ব্যবহার করে স্ট্রিং_্যাগের মতো অ্যারে_এগিতে নাল মানগুলি কীভাবে বাদ দেওয়া যায়?


101

যদি আমি array_aggনাম সংগ্রহ করতে ব্যবহার করি তবে আমি আমার নামগুলি কমা দ্বারা পৃথক করে পাই, তবে যদি nullমান থাকে তবে সেই শূন্যটিও সমষ্টিগতভাবে একটি নাম হিসাবে নেওয়া হয়। উদাহরণ স্বরূপ :

SELECT g.id,
       array_agg(CASE WHEN g.canonical = 'Y' THEN g.users ELSE NULL END) canonical_users,
       array_agg(CASE WHEN g.canonical = 'N' THEN g.users ELSE NULL END) non_canonical_users
FROM groups g
GROUP BY g.id;

এটি ন্যায়বিচারের ,Larry,Philপরিবর্তে ফিরে আসে Larry,Phil(আমার 9.1.2 এ, এটি দেখায় NULL,Larry,Phil)। হিসেবে এই বেহালার

পরিবর্তে, যদি আমি ব্যবহার string_agg(), আমার কেবল নাম মত (খালি কমা অথবা NULLs ছাড়া) দেখায় এখানে

সমস্যাটি হ'ল আমি Postgres 8.4সার্ভারে ইনস্টল করেছি এবং string_agg()সেখানে কাজ করি না। অ্যারে_এগজি স্ট্রিং_এজিজি () এর মতো কাজ করার কোনও উপায় আছে কি?


এই বিষয়ে পোস্টগ্র্রেএসকিউএল মেইলিং তালিকা থ্রেডটি দেখুন: postgresql.1045698.n5.nabble.com/…
ক্রেগ রিঞ্জার

আমি দুঃখিত, আমি মনে করি না যে এই থ্রেডের কোনও সমাধান আছে ..
দাউদ

এই থ্রেডে দুটি সমাধান রয়েছে। একটি হ'ল একটি ফাংশন তৈরি করা এবং অন্যটি (কেবল প্রস্তাবিত দেখানো হয়নি) আমি উত্তর দিয়েছি।
ক্লোডোলোডো নেটো

@ ক্লডোয়াল্ডো - সমস্ত সারিগুলিতে ('y', 'n') তে প্রচলিত হবে ... সুতরাং যেখানে ক্লজটি অপ্রয়োজনীয় বলে মনে হচ্ছে। সমস্যাটি হ'ল একটি গোষ্ঠীকরণের মধ্যে, যদি প্রমিত ক্ষেত্রের মান 'ওয়াই' হয় এবং আমরা '
দাউদ

ঠিক আছে. এখন আমি বুঝতে পেরেছি. আপডেটের উত্তরটি পরীক্ষা করুন।
ক্লোডোয়াল্ডো নেট

উত্তর:


28

এসকিউএল ফিডল

select
    id,
    (select array_agg(a) from unnest(canonical_users) a where a is not null) canonical_users,
    (select array_agg(a) from unnest(non_canonical_users) a where a is not null) non_canonical_users
from (
    SELECT g.id,
           array_agg(CASE WHEN g.canonical = 'Y' THEN g.users ELSE NULL END) canonical_users,
           array_agg(CASE WHEN g.canonical = 'N' THEN g.users ELSE NULL END) non_canonical_users
    FROM groups g
    GROUP BY g.id
) s

অথবা, সহজ এবং সস্তা হতে পারে array_to_stringযা ব্যবহার করে নালগুলি দূর করে:

SELECT
    g.id,
    array_to_string(
        array_agg(CASE WHEN g.canonical = 'Y' THEN g.users ELSE NULL END)
        , ','
    ) canonical_users,
    array_to_string(
        array_agg(CASE WHEN g.canonical = 'N' THEN g.users ELSE NULL END)
        , ','
    ) non_canonical_users
FROM groups g
GROUP BY g.id

এসকিউএল ফিডল


ধন্যবাদ তবে যদি প্রধান ক্যোয়ারী (গুলি) 1000 সারি দেয়, তবে 2 টি সাবকিউরিয় (অযৌক্তিক ব্যবহার করে) প্রতিটি সারির জন্য একবার চলবে .. 2000 অতিরিক্ত বাছাইকৃত অনুসন্ধানগুলি কার্যকর করার চেয়ে NULL সহ্য করা কি আরও ভাল হবে?
দাউদ

@ দাউদ নতুন সংস্করণ যা সস্তা হতে পারে। নিশ্চিত হওয়ার জন্য উভয়ের ব্যাখ্যা আউটপুট নিন।
ক্লোডোলোডো নেট

4
@ ক্লোডোলোডো আপনি যদি ব্যবহার করেন তবে আপনিও ব্যবহার array_to_string(array_agg(...))করতে পারেন string_agg
ক্রেগ রিঞ্জার

4
@ ক্রেইগ প্রশ্নে সমস্যাটি 8.4
ক্লোডোয়াল্ডো নেটো

@ ক্লডোয়াল্ডো গাহ, পুরানো সংস্করণ। ধন্যবাদ
ক্রেগ রিঞ্জার

256

Postgresql-9.3 এর মাধ্যমে কেউ এটি করতে পারে;

SELECT g.id,
   array_remove(array_agg(CASE WHEN g.canonical = 'Y' THEN g.users ELSE NULL END), NULL) canonical_users,
   array_remove(array_agg(CASE WHEN g.canonical = 'N' THEN g.users ELSE NULL END), NULL) non_canonical_users
FROM groups g 
GROUP BY g.id;

আপডেট : postgresql-9.4 সহ;

SELECT g.id,
   array_agg(g.users) FILTER (WHERE g.canonical = 'Y') canonical_users,
   array_agg(g.users) FILTER (WHERE g.canonical = 'N') non_canonical_users
FROM groups g 
GROUP BY g.id;

4
এটি কাজ করে এবং দ্রুত এবং মার্জিত, এটি আমাকে ওপি'র মতো একটি সমস্যা সমাধান করেছে। যারা এখনও এটি করেন নি তাদের জন্য 9.3 এ আপগ্রেড করার একটি কারণ। +1
পাভেল ভি।

12
9.4 আরও বেশি মার্জিত।
মোহন

4
9.4 ভেরিয়েন্টটি আরও ভাল, কারণ আমার ক্ষেত্রে আমার যা ফিল্টার করা দরকার তা হ'ল নালাগুলি।
কোল্ডিক্ট

আমি প্রথমে আপডেট হওয়া সংস্করণটি ব্যবহার করেছি, কিন্তু তারপরে বুঝতে পেরেছিলাম নুলস এবং ডুপ্লিকেটগুলি অপসারণ করার দরকার আছে, তাই প্রথম পরামর্শে ফিরে গিয়েছিলাম। এটি একটি বিশাল প্রশ্ন, তবে এটি একটি বস্তুগত দৃষ্টি তৈরি করা, সুতরাং কোনও বিশাল সমস্যা নয়।
পুনঃপ্রকাশ

12

অ্যারে সমষ্টি থেকে নালগুলি সরিয়ে ফেলার সাধারণ প্রশ্নটি সমাধান করার ক্ষেত্রে সমস্যাটি আক্রমণের দুটি প্রধান উপায় রয়েছে: হয় অ্যারে_্যাগ (অযাচিত (অ্যারে_অ্যাগ (এক্স)) করা বা একটি কাস্টম সমষ্টি তৈরি করা।

প্রথমটি উপরে প্রদর্শিত ফর্মটির :

SELECT 
    array_agg(u) 
FROM (
    SELECT 
        unnest(
            array_agg(v)
        ) as u 
    FROM 
        x
    ) un
WHERE 
    u IS NOT NULL;

দ্বিতীয়:

/*
With reference to
http://ejrh.wordpress.com/2011/09/27/denormalisation-aggregate-function-for-postgresql/
*/
CREATE OR REPLACE FUNCTION fn_array_agg_notnull (
    a anyarray
    , b anyelement
) RETURNS ANYARRAY
AS $$
BEGIN

    IF b IS NOT NULL THEN
        a := array_append(a, b);
    END IF;

    RETURN a;

END;
$$ IMMUTABLE LANGUAGE 'plpgsql';

CREATE AGGREGATE array_agg_notnull(ANYELEMENT) (
    SFUNC = fn_array_agg_notnull,
    STYPE = ANYARRAY,
    INITCOND = '{}'
);

দ্বিতীয়টিকে কল করা (স্বাভাবিকভাবে) প্রথমটির চেয়ে একটু সুন্দর দেখাচ্ছে:

এক্স থেকে অ্যারে_এজিজি_ন্টনাল (v) নির্বাচন করুন;


12

আপনি যদি অ্যারে থেকে কোনও এনএলএল অপসারণ করবেন সে সম্পর্কে সাধারণ প্রশ্নের আধুনিক উত্তর খুঁজছেন , তা হ'ল:

array_remove(your_array, NULL)

আমি অভিনয় সম্পর্কে বিশেষভাবে আগ্রহী ছিলাম এবং এটি সেরা সম্ভাব্য বিকল্পের সাথে তুলনা করতে চেয়েছিলাম:

CREATE OR REPLACE FUNCTION strip_nulls(
    IN array_in ANYARRAY
)
RETURNS anyarray AS
'
SELECT
    array_agg(a)
FROM unnest(array_in) a
WHERE
    a IS NOT NULL
;
'
LANGUAGE sql
;

পেগবেঞ্চ পরীক্ষা করা প্রমাণিত হয়েছে (উচ্চ আত্মবিশ্বাসের সাথে) যে অ্যারে_রেমোভ () তত দ্রুত দ্বিগুণ চেয়ে দ্বিগুণ । আমি বিভিন্ন অ্যারে আকারের (10, 100 এবং 1000 উপাদান) এবং এর মধ্যে এলোমেলো NULL সহ ডাবল নির্ভুলতা সংখ্যায় আমার পরীক্ষা করেছিলাম।


এটিও লক্ষণীয় যে এগুলি ফাঁকা অপসারণ করতে ব্যবহার করা যেতে পারে (''! = NULL)। তবে দ্বিতীয় প্যারামিটারটি গ্রহণ করে anyelementএবং সম্ভবত যেহেতু তারা সম্ভবত একটি স্ট্রিং আক্ষরিক একটি ফাঁকা ইঙ্গিত দিচ্ছে, তাই আপনি যে ফর্মটি চান তা সাধারণত নন-অ্যারেতে কাস্ট করার বিষয়টি নিশ্চিত করুন।

উদাহরণ স্বরূপ:

select array_remove(array['abc', ''], ''::text);

যদি তুমি চেষ্টা কর:

select array_remove(array['abc', ''], '');

এটি ধরে নেবে যে '' হ'ল পাঠ্য [] (অ্যারে) এবং এই ত্রুটিটি ফেলে দেবে:

ত্রুটি: ত্রুটিযুক্ত অ্যারে আক্ষরিক: ""


@ বিবেক সিংহ আপনি পোস্টগ্রিসের কোন সংস্করণ ব্যবহার করছেন? আমি আপনার প্রশ্নের সবেমাত্র পরীক্ষা করেছি এবং এটি আমার জন্য "{1,2,3}" এর ফলস্বরূপ। আমি 12.1 ব্যবহার করছি।
অ্যালেক্সি থিওডোর

আহা, আমি @ অ্যালেক্সি-থিওডোরটি দেখছি আমার শেষের দিকে কী ঘটছে। আমি একটি কাস্টম + পরিবর্তিত পোস্টগ্রিজ ড্রাইভার ব্যবহার করছিলাম। আমি যখন সরাসরি কনসোলে জিজ্ঞাসা করি তখন আমি সঠিক আউটপুট দেখতে পারি! বিভ্রান্তির জন্য দুঃখিত। মুছে ফেলা পূর্বের মন্তব্য এবং upvated উত্তর!
বিবেক সিনহা

সম্ভবত এটি উল্লেখ করা সহায়ক যে অ্যারে_রেমভ 9.3
আনাতোলি রুগালেভ

9

এই থ্রেডটি বেশ পুরানো হলেও আমি এটি যুক্ত করছি, তবে আমি এই ঝরঝরে কৌতুকের দিকে ছুটে এসেছি যা ছোট অ্যারেগুলিতে বেশ ভাল কাজ করে। এটি অতিরিক্ত গ্রন্থাগার বা ফাংশন ছাড়াই পোস্টগ্রিস 8.4+ এ চলে।

string_to_array(array_to_string(array_agg(my_column)))::int[]

array_to_string()পদ্ধতি আসলে NULLs পরিত্রাণ পায়।


3

মন্তব্যে যেমন পরামর্শ দেওয়া হয়েছে আপনি একটি অ্যারেতে নাল প্রতিস্থাপনের জন্য একটি ফাংশন লিখতে পারেন, তবে মন্তব্যে লিঙ্কযুক্ত থ্রেডেও উল্লেখ করেছেন, এই ধরণের সামগ্রিক ফাংশনটির দক্ষতা হ্রাস করে যদি আপনাকে একটি সামগ্রিক তৈরি করতে হয় তবে , এটি বিভক্ত করুন এবং আবার এটি একত্রিত করুন।

আমি মনে করি অ্যারেতে নালগুলি রাখা কেবল অ্যারে_আগের (সম্ভবত অযাচিত) বৈশিষ্ট্য। এটি এড়াতে আপনি সাবকিউরিগুলি ব্যবহার করতে পারেন:

SELECT  COALESCE(y.ID, n.ID) ID,
        y.Users,
        n.Users
FROM    (   SELECT  g.ID, ARRAY_AGG(g.Users) AS Users
            FROM    Groups g
            WHERE   g.Canonical = 'Y'
            GROUP BY g.ID
        ) y
        FULL JOIN 
        (   SELECT  g.ID, ARRAY_AGG(g.Users) AS Users
            FROM    Groups g
            WHERE   g.Canonical = 'N'
            GROUP BY g.ID
        ) n
            ON n.ID = y.ID

এসকিউএল ফিডল


ধন্যবাদ তবে একটি নির্দিষ্ট গ্রুপিংয়ের মধ্যে সারিগুলি হ্যান্ডেল করার জন্য আমার 'কেস' দরকার ছিল, এবং সাবকিউরিগুলি সেখানে অকার্যকর হবে
দাউদ

0

এটি খুব সহজ, প্রথমত পাঠ্যের জন্য একটি নতুন - (বিয়োগ) অপারেটর তৈরি করুন [] :

CREATE OR REPLACE FUNCTION diff_elements_text
    (
        text[], text[] 
    )
RETURNS text[] as 
$$
    SELECT array_agg(DISTINCT new_arr.elem)
    FROM
        unnest($1) as new_arr(elem)
        LEFT OUTER JOIN
        unnest($2) as old_arr(elem)
        ON new_arr.elem = old_arr.elem
    WHERE old_arr.elem IS NULL
$$ LANGUAGE SQL IMMUTABLE;

CREATE OPERATOR - (
    PROCEDURE = diff_elements_text,
    leftarg = text[],
    rightarg = text[]
);

এবং কেবল অ্যারেটি বিয়োগ করুন [নাল]:

select 
    array_agg(x)-array['']
from
    (   select 'Y' x union all
        select null union all
        select 'N' union all
        select '' 
    ) x;

এখানেই শেষ:

{Y, N


4
array_agg(x) FILTER (WHERE x is not null)অনেক সহজ মনে হচ্ছে: dbfiddle.uk/… এবং আপনার নিজের ফাংশনটির সত্যই দরকার নেই, আপনি কেবল array_remove() dbfiddle.uk/…
a_horse_with_no_name

-6

আরও বড় প্রশ্ন হ'ল কেন একই সাথে সমস্ত ব্যবহারকারী / গোষ্ঠী কম্বোকে টানুন। গ্যারান্টিযুক্ত আপনার ইউআই ক্যান্ট সেই সমস্ত ডেটা হ্যান্ডেল করতে পারে। বড় আকারের ডেটাতে পেজিং যুক্ত করাও একটি খারাপ ধারণা। আপনার ব্যবহারকারীরা ডেটা দেখার আগে সেটটি ফিল্টার করতে পান। আপনার JOIN বিকল্প সেট তালিকায় রয়েছে তা নিশ্চিত করুন যাতে তারা চাইলে পারফরম্যান্সের জন্য ফিল্টার করতে পারে। কখনও কখনও 2 টি প্রশ্ন যদি উভয়ই দ্রুত হয় তবে ব্যবহারকারীরা আরও সুখী হয়।

আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.