Postgres: แตกต่างกัน แต่สำหรับคอลัมน์เดียว


121

ฉันมีตารางใน pgsql ที่มีชื่อ (มีมากกว่า 1 แถว mio) แต่ฉันก็มีรายการที่ซ้ำกันมากมาย ผมเลือก 3 idสาขา: name, metadata,

ฉันต้องการเลือกแบบสุ่มด้วยORDER BY RANDOM()และLIMIT 1000ดังนั้นฉันจึงทำเช่นนี้หลายขั้นตอนเพื่อบันทึกหน่วยความจำในสคริปต์ PHP ของฉัน

แต่ฉันจะทำเช่นนั้นได้อย่างไรเพื่อให้มีรายชื่อที่ไม่มีชื่อซ้ำกัน

ตัวอย่าง[1,"Michael Fox","2003-03-03,34,M,4545"]จะถูกส่งกลับ [2,"Michael Fox","1989-02-23,M,5633"]แต่ไม่ ช่องชื่อมีความสำคัญที่สุดและต้องไม่ซ้ำกันในรายการทุกครั้งที่เลือกและต้องสุ่ม

ฉันลองด้วยGROUP BY namebu แล้วคาดว่าฉันจะมี id และ metadata ในGROUP BYเช่นกันหรือในฟังก์ชัน aggragate แต่ฉันไม่ต้องการให้มีการกรองอย่างใด

มีใครรู้วิธีดึงข้อมูลหลายคอลัมน์ แต่แยกเฉพาะคอลัมน์เดียว

คำตอบ:


226

ในการสร้างความแตกต่างในคอลัมน์เดียว (หรือ n) คอลัมน์:

select distinct on (name)
    name, col1, col2
from names

สิ่งนี้จะส่งคืนแถวใดก็ได้ที่มีชื่อ หากคุณต้องการควบคุมว่าจะส่งคืนแถวใดคุณต้องสั่งซื้อ:

select distinct on (name)
    name, col1, col2
from names
order by name, col1

จะส่งคืนแถวแรกเมื่อสั่งโดย col1

distinct on:

SELECT DISTINCT ON (นิพจน์ [, ... ]) เก็บเฉพาะแถวแรกของแต่ละชุดของแถวที่นิพจน์ที่กำหนดประเมินว่าเท่ากัน นิพจน์ DISTINCT ON ถูกตีความโดยใช้กฎเดียวกันกับ ORDER BY (ดูด้านบน) โปรดทราบว่า "แถวแรก" ของแต่ละชุดนั้นไม่สามารถคาดเดาได้เว้นแต่จะใช้ ORDER BY เพื่อให้แน่ใจว่าแถวที่ต้องการปรากฏก่อน

นิพจน์ DISTINCT ON ต้องตรงกับนิพจน์ ORDER BY ซ้ายสุด โดยปกติคำสั่ง ORDER BY จะมีนิพจน์เพิ่มเติมที่กำหนดลำดับความสำคัญที่ต้องการของแถวภายในแต่ละกลุ่ม DISTINCT ON


จับได้ดีในการสั่งซื้อ ฉันไม่ได้รวมไว้เพราะพวกเขาบอกว่าต้องการสั่งซื้อแบบสุ่ม แต่สิ่งสำคัญคือต้องพูดถึงอยู่ดี
Craig Ringer

เป็นorder by nameต้อง? มันจะให้ผลลัพธ์ที่แตกต่างกับorder by col1?
Elliot Chance

1
@elliot ใช่nameเป็นสิ่งจำเป็น ตรวจสอบdistinct onที่คู่มือ
Clodoaldo Neto

1
ฉันหวังว่าทีม TSQL สามารถจัดหาวิธีที่สมเหตุสมผลในการดำเนินการนี้
JTW


17

มีใครรู้วิธีดึงข้อมูลหลายคอลัมน์ แต่แยกเฉพาะคอลัมน์เดียว

คุณต้องการข้อDISTINCT ON

คุณไม่ได้ให้ข้อมูลตัวอย่างหรือแบบสอบถามทั้งหมดดังนั้นฉันจึงไม่มีอะไรจะแสดงให้คุณเห็น คุณต้องการเขียนสิ่งที่ชอบ:

SELECT DISTINCT ON (name) fields, id, name, metadata FROM the_table;

สิ่งนี้จะส่งคืนชุดแถวที่คาดเดาไม่ได้ (แต่ไม่ใช่ "สุ่ม") หากคุณต้องการให้คาดเดาได้ให้เพิ่มORDER BYคำตอบของ Clodaldo ORDER BY random()หากคุณต้องการที่จะให้มันสุ่มอย่างแท้จริงคุณจะต้องการที่จะ


เพียงสังเกตว่าคำสั่ง DISTINCT ON นี้คุณสามารถสั่งซื้อด้วยสิ่งเดียวกันเท่านั้น + เพิ่มเติม ดังนั้นถ้าคุณพูดว่า DISTINCT ON (ชื่อ) คุณต้องสั่งซื้อตามชื่อแล้วอะไรก็ได้ที่คุณต้องการ แทบจะไม่เหมาะ
Kevin Parker

Kevin คุณสามารถใช้ CTE หรือแบบสอบถามย่อยใน FROM และ ORDER BY ในแบบสอบถามภายนอก
Craig Ringer

ใช่และดูประสิทธิภาพไป ... ผลลัพธ์ที่เป็นไปได้ทั้งหมดจากพื้นที่ดัชนีจะถูกค้นหา มันเปลี่ยนสิ่งที่อาจเป็นแบบสอบถาม 10-20 มิลลิวินาทีที่มีดัชนีที่ถูกต้องเป็นหนึ่ง 900 มิลลิวินาทีเพียงเพราะตำแหน่งไม่สามารถจัดการกับคำสั่ง / ลำดับที่แตกต่างกันได้ ไม่สำคัญว่าลำดับการสืบค้นภายนอกคืออะไร แต่จะใช้ดัชนีจากแบบสอบถามย่อยภายในเพื่อค้นหารายการที่ตรงกันก่อนจากนั้นจึงเรียงลำดับใหม่ ยินดีจ่ายค่าที่ปรึกษาสำหรับการแก้ปัญหาอย่างแท้จริงที่dba.stackexchange.com/questions/260852/…
Kevin Parker

4
SELECT NAME,MAX(ID) as ID,MAX(METADATA) as METADATA 
from SOMETABLE
GROUP BY NAME

2
คำเตือน: นั่นอาจไม่ส่งคืนค่า ID หรือค่าข้อมูลเมตาที่เป็น "together"
a_horse_with_no_name

@Novum ไม่ได้หมายความว่าแมวรับค่า id จากแถวหนึ่งของ Michael และข้อมูลเมตาจากอีกแถวตามที่ถามหา Michael's maxes
Clodoaldo Neto

ใช่มันขึ้นอยู่กับการใช้ข้อมูลจริงของ OP อย่างมากซึ่งฉันไม่รู้เลย คุณอาจต้องใช้ MIN หรืออะไรก็ได้ แสดงให้เห็นว่าคุณสามารถรวมเขตข้อมูลที่ไม่อยู่ในGROUP BYประโยคได้อย่างไร
David Jashi

นี่ไม่ใช่วิธีแก้ปัญหาที่ดีเพราะค่าต่างๆจากแถวต่างๆจะผสมกัน
Elliot Chance
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.