كيف لسلسلة سلاسل من سلسلة الميدانية في كيو 'مجموعة' query ؟

StackOverflow https://stackoverflow.com/questions/43870

سؤال

أنا أبحث عن طريقة لسلسلة سلاسل من حقل ضمن مجموعة من الاستعلام.لذلك على سبيل المثال ، لدي جدول:

ID   COMPANY_ID   EMPLOYEE
1    1            Anna
2    1            Bill
3    2            Carol
4    2            Dave

وأردت أن مجموعة من company_id أن تحصل على شيء مثل:

COMPANY_ID   EMPLOYEE
1            Anna, Bill
2            Carol, Dave

هناك المدمج في وظيفة في الخلية للقيام بذلك group_concat

هل كانت مفيدة؟

المحلول

كيو 9.0 أو أحدث:

الإصدارات الأخيرة من بوستجرس (منذ أواخر عام 2010) يكون string_agg(expression, delimiter) وظيفة والتي سوف تفعل بالضبط ما السؤال ، حتى يتيح لك تحديد محدد السلسلة:

SELECT company_id, string_agg(employee, ', ')
FROM mytable
GROUP BY company_id;

بوستجرس 9.0 وأضاف أيضا القدرة على تحديد ORDER BY شرط في أي الكلي التعبير;وإلا فإن أمر غير معروف.بحيث يمكنك الآن كتابة:

SELECT company_id, string_agg(employee, ', ' ORDER BY employee)
FROM mytable
GROUP BY company_id;

أو في الواقع:

SELECT string_agg(actor_name, ', ' ORDER BY first_appearance)

كيو 8.4 أو في وقت لاحق:

كيو 8.4 (في عام 2009) قدم دالة تجميع array_agg(expression) الذي يسلسل القيم في صفيف.ثم array_to_string() يمكن أن تستخدم لإعطاء النتيجة المرجوة:

SELECT company_id, array_to_string(array_agg(employee), ', ')
FROM mytable
GROUP BY company_id;

string_agg قبل 9.0 إصدارات:

في حالة أي شخص يأتي عبر هذا تبحث عن متوافق مع شيم قبل 9.0 قواعد البيانات ، فمن الممكن أن تنفذ في كل شيء string_agg باستثناء ORDER BY البند.

حتى مع أقل من تعريف هذا يجب أن تعمل نفس في 9.x بوستجرس DB:

SELECT string_agg(name, '; ') AS semi_colon_separated_names FROM things;

لكن هذا سيكون خطأ في بناء الجملة:

SELECT string_agg(name, '; ' ORDER BY name) AS semi_colon_separated_names FROM things;
--> ERROR: syntax error at or near "ORDER"

اختبار على الإنترنت 8.3.

CREATE FUNCTION string_agg_transfn(text, text, text)
    RETURNS text AS 
    $$
        BEGIN
            IF $1 IS NULL THEN
                RETURN $2;
            ELSE
                RETURN $1 || $3 || $2;
            END IF;
        END;
    $$
    LANGUAGE plpgsql IMMUTABLE
COST 1;

CREATE AGGREGATE string_agg(text, text) (
    SFUNC=string_agg_transfn,
    STYPE=text
);

مخصص الاختلافات (كل بوستجرس الإصدارات)

قبل 9.0, لم يكن هناك المدمج في وظيفة الكلي لسلسلة السلاسل.أبسط مخصص تنفيذ (اقترح Vajda جابو في القائمة البريدية البريد, من بين العديد من الآخرين) هو استخدام المدمج في textcat وظيفة (التي تقع خلف || المشغل):

CREATE AGGREGATE textcat_all(
  basetype    = text,
  sfunc       = textcat,
  stype       = text,
  initcond    = ''
);

هنا CREATE AGGREGATE وثائق.

هذا ببساطة يلصق كل الخيوط معا ، مع عدم وجود فاصل.من أجل الحصول على " ، " إدراج بينهما دون وجود لها في نهاية المطاف ، قد ترغب في جعل الخاصة بك سلسلة وظيفة بديلا عن "textcat" أعلاه.هنا هو واحد لقد وضعت واختبارها على 8.3.12:

CREATE FUNCTION commacat(acc text, instr text) RETURNS text AS $$
  BEGIN
    IF acc IS NULL OR acc = '' THEN
      RETURN instr;
    ELSE
      RETURN acc || ', ' || instr;
    END IF;
  END;
$$ LANGUAGE plpgsql;

هذا الإصدار سيتم إخراج فاصلة حتى إذا كانت القيمة في الصف فارغة أو فارغة, حتى تحصل على إخراج مثل هذا:

a, b, c, , e, , g

إذا كنت تفضل أن إزالة إضافية الفواصل إلى إخراج هذا:

a, b, c, e, g

ثم إضافة ELSIF تحقق من أن وظيفة مثل هذا:

CREATE FUNCTION commacat_ignore_nulls(acc text, instr text) RETURNS text AS $$
  BEGIN
    IF acc IS NULL OR acc = '' THEN
      RETURN instr;
    ELSIF instr IS NULL OR instr = '' THEN
      RETURN acc;
    ELSE
      RETURN acc || ', ' || instr;
    END IF;
  END;
$$ LANGUAGE plpgsql;

نصائح أخرى

كيف حول استخدام بوستجرس المدمج في مجموعة الوظائف ؟ على الأقل على 8.4 هذا يعمل من خارج منطقة الجزاء:

SELECT company_id, array_to_string(array_agg(employee), ',')
FROM mytable
GROUP BY company_id;

كما من كيو 9.0 يمكنك استخدام دالة تجميع يسمى string_agg.الجديد الخاص بك SQL ينبغي أن ننظر بشيء من هذا القبيل:

SELECT company_id, string_agg(employee, ', ')
FROM mytable
GROUP BY company_id;

لا تدعي أي الائتمان عن الجواب لأنني وجدت أنه بعد بعض البحث:

ما لم أكن أعرفه هو أن الإنترنت يسمح لك لتحديد الخاصة بك وظائف الكلي مع إنشاء الكلي

هذا المنصب على كيو قائمة يبين كيف تافهة هو لخلق وظيفة للقيام بما هو مطلوب:

CREATE AGGREGATE textcat_all(
  basetype    = text,
  sfunc       = textcat,
  stype       = text,
  initcond    = ''
);

SELECT company_id, textcat_all(employee || ', ')
FROM mytable
GROUP BY company_id;

كما سبق ذكره, إنشاء الخاصة بك وظيفة الكلي هو الشيء الصحيح القيام به.هنا هو بلدي سلسلة الكلي وظيفة (يمكنك العثور على التفاصيل في الفرنسية):

CREATE OR REPLACE FUNCTION concat2(text, text) RETURNS text AS '
    SELECT CASE WHEN $1 IS NULL OR $1 = \'\' THEN $2
            WHEN $2 IS NULL OR $2 = \'\' THEN $1
            ELSE $1 || \' / \' || $2
            END; 
'
 LANGUAGE SQL;

CREATE AGGREGATE concatenate (
  sfunc = concat2,
  basetype = text,
  stype = text,
  initcond = ''

);

ومن ثم استخدامها مثل:

SELECT company_id, concatenate(employee) AS employees FROM ...

هذا الإعلان أحدث قائمة مقتطف قد تكون ذات فائدة إذا كنت سوف تكون الترقية إلى 8.4:

حتى 8.4 يخرج مع سوبر-effient الأم واحدة ، يمكنك إضافة على array_accum() وظيفة في كيو وثائق المتداول أي عمود في صفيف ، والتي يمكن ثم يتم استخدامها من قبل تطبيق قانون أو جنبا إلى جنب مع array_to_string() إلى تنسيق قائمة:

http://www.postgresql.org/docs/current/static/xaggr.html

أود الارتباط إلى 8.4 التنمية مستندات ولكن لا يبدو أن قائمة هذه الميزة حتى الآن.

متابعة كيف رد باستخدام بوستجرس مستندات:

أولا إنشاء مجموعة من العناصر ، ثم استخدام المدمج في array_to_string وظيفة.

CREATE AGGREGATE array_accum (anyelement)
(
 sfunc = array_append,
 stype = anyarray,
 initcond = '{}'
);

select array_to_string(array_accum(name),'|') from table group by id;

التالية مرة أخرى على استخدام مخصص الكلي وظيفة من سلسلة سلسلة:كنت بحاجة إلى أن نتذكر أن select سوف المكان الصفوف في أي أمر ، لذلك سوف تحتاج إلى القيام به دون حدد في من البيان مع النظام شرط ثم الخارجي حدد مع مجموعة من شرط أن تجميع سلاسل, وبالتالي:

SELECT custom_aggregate(MY.special_strings)
FROM (SELECT special_strings, grouping_column 
        FROM a_table 
        ORDER BY ordering_column) MY
GROUP BY MY.grouping_column

لقد وجدت هذه كيو الوثائق المفيدة: http://www.postgresql.org/docs/8.0/interactive/functions-conditional.html.

في حالتي أنا سعى عادي SQL لسلسلة حقل مع أقواس حول ذلك ، إذا كان الحقل غير فارغة.

select itemid, 
  CASE 
    itemdescription WHEN '' THEN itemname 
    ELSE itemname || ' (' || itemdescription || ')' 
  END 
from items;

استخدام STRING_AGG وظيفة كيو و جوجل BigQuery SQL:

SELECT company_id, STRING_AGG(employee, ', ')
FROM employees
GROUP BY company_id;

وفقا النسخة كيو 9.0 فما فوق يمكنك استخدام دالة تجميع يسمى string_agg.الجديد الخاص بك SQL ينبغي أن ننظر بشيء من هذا القبيل:

SELECT company_id, string_agg(employee, ', ')
    FROM mytable GROUP BY company_id;

يمكنك أيضا استخدام تنسيق وظيفة.والتي يمكن أيضا ضمنا تأخذ الرعاية من نوع التحويل من النص ، الباحث ، وما إلى ذلك من تلقاء نفسه.

create or replace function concat_return_row_count(tbl_name text, column_name text, value int)
returns integer as $row_count$
declare
total integer;
begin
    EXECUTE format('select count(*) from %s WHERE %s = %s', tbl_name, column_name, value) INTO total;
    return total;
end;
$row_count$ language plpgsql;


postgres=# select concat_return_row_count('tbl_name','column_name',2); --2 is the value

أنا باستخدام Jetbrains رايدر و كان من المتاعب نسخ النتائج من الأمثلة المذكورة أعلاه إلى إعادة تنفيذ لأنه يبدو أن التفاف كل شيء في JSON.هذا وتشارك في بيان أنه كان من الأسهل لتشغيل

select string_agg('drop table if exists "' || tablename || '" cascade', ';') 
from pg_tables where schemaname != $$pg_catalog$$ and tableName like $$rm_%$$

إذا كنت على الأمازون الانزياح نحو الأحمر ، حيث string_agg غير معتمد ، حاول استخدام listagg.

SELECT company_id, listagg(EMPLOYEE, ', ') as employees
FROM EMPLOYEE_table
GROUP BY company_id;
مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top