Postgresql GROUP_CONCAT เทียบเท่าหรือไม่


248

ฉันมีตารางและฉันต้องการดึงหนึ่งแถวต่อหนึ่ง id ด้วยค่าเขตข้อมูลที่ต่อกัน

ตัวอย่างเช่นในตารางของฉันฉันมีสิ่งนี้:

TM67 | 4  | 32556
TM67 | 9  | 98200
TM67 | 72 | 22300
TM99 | 2  | 23009
TM99 | 3  | 11200

และฉันต้องการที่จะส่งออก:

TM67 | 4,9,72 | 32556,98200,22300
TM99 | 2,3    | 23009,11200

ใน MySQL ฉันสามารถใช้ฟังก์ชันการรวมGROUP_CONCATแต่ดูเหมือนจะไม่ทำงานที่นี่ ... มี PostgreSQL ที่เท่ากันหรือวิธีอื่นในการทำสิ่งนี้


ไม่ได้เป็นคำตอบ แต่เช็คเอาท์postgresonline.com/journal/index.php?/archives/...
Kuberchaun


เป็นไปได้ที่ซ้ำกันของฟังก์ชันการจำลอง group_concat MySQL ใน SQL Server
ntalbs

1
ฉันคิดว่าคำตอบที่ดีที่สุดยังอยู่ในคำถามอื่น: stackoverflow.com/a/47638417/243233
Jus12

คำตอบ:


237

นี่อาจเป็นจุดเริ่มต้นที่ดี (เฉพาะรุ่น 8.4 ขึ้นไป):

SELECT id_field, array_agg(value_field1), array_agg(value_field2)
FROM data_table
GROUP BY id_field

array_aggส่งคืนอาร์เรย์ แต่คุณสามารถส่งไปที่ข้อความและแก้ไขได้ตามต้องการ (ดูคำอธิบายด้านล่าง)

ก่อนเวอร์ชัน 8.4 คุณต้องกำหนดด้วยตนเองก่อนใช้งาน:

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

(ถอดความจากเอกสาร PostgreSQL)

ชี้แจง:

  • ผลที่ได้จากการคัดเลือกอาเรย์เป็นข้อความคือสตริงผลลัพธ์เริ่มต้นและสิ้นสุดด้วยเครื่องหมายปีกกา เครื่องมือจัดฟันเหล่านั้นจำเป็นต้องลบออกโดยวิธีการบางอย่างถ้าไม่ต้องการ
  • การส่ง ANYARRAY ไปยัง TEXT ที่ดีที่สุดจำลองเอาต์พุต CSV เป็นองค์ประกอบที่มีเครื่องหมายจุลภาคที่ฝังอยู่จะถูกอ้างอิงสองครั้งในเอาต์พุตในสไตล์ CSV มาตรฐาน ทั้ง array_to_string () หรือ string_agg () (ฟังก์ชั่น "group_concat" ที่เพิ่มเข้ามาใน 9.1) สตริงคำพูดที่มีเครื่องหมายจุลภาคฝังตัวส่งผลให้จำนวนองค์ประกอบที่ไม่ถูกต้องในรายการผลลัพธ์
  • ใหม่ 9.1 string_agg () ฟังก์ชั่นไม่ได้ส่งผลภายในเพื่อ TEXT ก่อน ดังนั้น "string_agg (value_field)" จะสร้างข้อผิดพลาดถ้า value_field เป็นจำนวนเต็ม ต้องระบุ "string_agg (value_field :: text)" วิธีการ array_agg () ต้องใช้การร่ายเพียงครั้งเดียวหลังจากการรวม (แทนที่จะใช้การคำนวณต่อมูลค่า)

1
และใน 9.0 คุณจะมี listagg ()
Scott Bailey

6
ในการรับ CSV แบบสอบถามควรเป็น: SELECT id_field, array_to_string (array_agg (value_field1), ','), array_to_string (array_agg (value_field2), ',') จากกลุ่ม data_table ตาม id_field
Nux

2
คุณไม่สามารถใช้ array_to_string ได้ทุกกรณีที่นี่ หาก value_field ของคุณมีเครื่องหมายจุลภาคที่ฝังอยู่ CSV ที่ได้จะไม่ถูกต้อง การใช้ array_agg () และการส่งข้อความไปยัง TEXT จะต้องใส่เครื่องหมายคำพูดอย่างถูกต้องด้วยเครื่องหมายจุลภาคในตัว ข้อแม้เดียวคือมันยังรวมถึงการจัดฟันหยิกเริ่มต้นและสิ้นสุดดังนั้นคำสั่งของฉัน "และแก้ไขได้ตามต้องการ" ฉันจะแก้ไขเพื่อชี้แจงจุดนั้น
Matthew Wood

FYI: นี่คือลิงก์ไปยังเอกสารใน array_agg ใน 8.4
Michael Rusch

256

ตั้งแต่ 9.0สิ่งนี้ง่ายยิ่งขึ้น:

SELECT id, 
       string_agg(some_column, ',')
FROM the_table
GROUP BY id

32
โปรดทราบว่าไวยากรณ์ยังช่วยให้คุณสามารถระบุลำดับของค่าในสตริง (หรืออาร์เรย์, การใช้array_agg) เช่นstring_agg(some_column, ',' ORDER BY some_column)หรือแม้กระทั่งstring_agg(surname || ', ' || forename, '; ' ORDER BY surname, forename)
IMSoP

8
มันยอดเยี่ยมที่ใช้distinctงานได้กับ string_agg ดังนั้นจึงสามารถใช้งานได้string_agg(distinct some_solumn, ',')
arun

3
โปรดทราบว่าคุณอาจจำเป็นต้องแปลงค่าคอลัมน์เป็นค่าที่TEXTไม่ใช่ค่าสตริง (เช่นuuid) จะมีลักษณะเช่นนี้string_agg(some_column::text, ',')
Kendall

48
SELECT array_to_string(array(SELECT a FROM b),', ');

จะทำเช่นกัน


เป็นไปได้ไหมที่จะทำอะไรบางอย่างในความคิดเห็นนี้ที่คุณรวมอยู่ในลำดับที่แน่นอน? คุณจะจัดการการจัดกลุ่มตามคอลัมน์หนึ่งได้อย่างไรและจัดเรียงโดยคอลัมน์อื่น (ตัวอย่างเช่นเพื่อเชื่อมโยงตัวแปรภายในชุดข้อมูลระยะยาว)
Michael


2

และรุ่นที่ใช้งานกับประเภทอาเรย์ :

select
  array_to_string(
    array(select distinct unnest(zip_codes) from table),
    ', '
);

คำตอบที่ซ้ำกัน @max_spy พูดสิ่งเดียวกันเมื่อห้าปีก่อน
Emil Vikström

@ EmilVikström: คุณมีสิทธิ์ที่จะผิด แต่อ่านอย่างระมัดระวัง มันไม่เพียง แต่แตกต่างกัน แต่ฉันให้เป็นตัวอย่างที่ทำงานร่วมกับชนิดอาร์เรย์ที่ชอบ - zip_codes character varying(5)[]เป็น นอกจากนี้ผมได้ยืนยันว่าสำหรับวัตถุประสงค์ของฉัน - unnest ERROR: cannot accumulate arrays of different dimensionalityเป็นสิ่งจำเป็นมิฉะนั้นคุณจะเห็น
Sławomir Lenart

1

ความแออัดของฉันใน postgresql

SELECT cpf || ';' || nome || ';' || telefone  
FROM (
      SELECT cpf
            ,nome
            ,STRING_AGG(CONCAT_WS( ';' , DDD_1, TELEFONE_1),';') AS telefone 
      FROM (
            SELECT DISTINCT * 
            FROM temp_bd 
            ORDER BY cpf DESC ) AS y
      GROUP BY 1,2 ) AS x   

1
ทำไมคุณถึงทำORDER BYในแบบสอบถามภายใน? การสั่งซื้อจะไม่สูญหายไปหรือไม่
mypetlion

-1

หวังว่าแบบสอบถามด้านล่างของ Oracle จะใช้งานได้

Select First_column,LISTAGG(second_column,',') 
    WITHIN GROUP (ORDER BY second_column) as Sec_column, 
    LISTAGG(third_column,',') 
    WITHIN GROUP (ORDER BY second_column) as thrd_column 
FROM tablename 
GROUP BY first_column

ฉันทดสอบในrextester.com/l/postgresql_online_compilerและไม่ทำงาน: 42883: ฟังก์ชั่น listagg (ข้อความ, ไม่ทราบ, ข้อความ) ไม่มีอยู่
Manuel Romeiro

Oracle มีไวยากรณ์และฟังก์ชันที่แตกต่างจาก postgres
Herman J. Radtke III
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.