2014-06-26 9 views
5

मैं पोस्टग्रेस्क्ल 9.3 में array_agg फ़ंक्शन को समझने की कोशिश कर रहा हूं। मैंने उन सभी के लिए एक मजेदार उदाहरण रखा है जो भाग लेने में रूचि रख सकते हैं।पोस्टग्रेस्क्ल 9.3 - array_agg चुनौती

1 9 80 के दशक से अमेरिकी फिल्मों का कोई प्रशंसक "ब्रैट पैक" से परिचित हो सकता है जो कई हिट फिल्मों में एक साथ दिखाई देता है। विकिपीडिया पर ब्रैट पैक फिल्मों के बारे में जानकारी का उपयोग करके, मैंने टेबल तैयार किए हैं जो एक साथ जुड़ने के बाद, हमें बता सकते हैं कि एक दूसरे के साथ काम किसने किया - अगर हमारे पास सही सवाल है!

/* 
See: http://en.wikipedia.org/wiki/Brat_Pack_(actors) 
*/ 

CREATE TABLE actor(
    id SERIAL PRIMARY KEY, 
    name VARCHAR(50) 
); 
insert into actor(name) values ('Emilio Estevez'),('Anthony Michael Hall'),('Rob Lowe'),('Andrew McCarthy'),('Demi Moore'),('Judd Nelson'),('Molly Ringwald'),('Ally Sheedy') 

CREATE TABLE movie(
    id SERIAL PRIMARY KEY, 
    title VARCHAR(200) 
); 
insert into movie(title) values ('The Outsiders'),('Class'),('Sixteen Candles'),('Oxford Blues'),('The Breakfast Club'),('St. Elmos Fire'), 
('Pretty in Pink'),('Blue City'),('About Last Night'),('Wisdom'), ('Fresh Horses'),('Betsys Wedding'),('Hail Caesar'); 

CREATE TABLE movie_brats(
    id SERIAL PRIMARY KEY, 
    movie_id INT REFERENCES movie(id), 
    actor_id INT REFERENCES actor(id) 
); 
insert into movie_brats(movie_id, actor_id) values (1,1),(1,3),(2,3),(2,4),(3,2),(3,7),(4,3),(4,8),(5,1),(5,2),(5,6), 
(5,7),(5,8),(6,1),(6,3),(6,4),(6,5),(6,6),(6,8),(7,4),(7,7),(8,6),(8,8),(9,3),(9,5),(10,1),(10,5),(11,4),(11,7), 
(12,7),(12,8),(13,2),(13,6); 

क्वेरी: की एक अलग सूची है जो लड़का पैक के प्रत्येक सदस्य के साथ काम किया, दोनों स्तंभों में नाम द्वारा आदेश दिया दिखाएँ

Name      Worked With 
---------------------------------------------------------------------------------------------------------------- 
Emelio Estevez  | Emilio Estevez, Anthony Michael Hall, Rob Lowe, Andrew McCarthy, Demi Moore, Judd Nelson, Molly Ringwald, Ally Sheedy 
*/ 

मेरे टूट क्वेरी:

select a1.name, array_to_string(array_agg(a2.name),', ') as Co_Stars 
from actor a1, actor a2, movie m, movie_brats mb 
where 
    m.id = mb.movie_id 
    and a1.id = mb.actor_id 
    and a2.id = mb.actor_id 
group by a1.id 
+1

एक ओर ध्यान दें: आप शायद 'string_agg() चाहते हैं' 'array_to_string का एक संयोजन के बजाय()' और 'array_agg() ' –

+0

मैंने अधिक संक्षिप्त आउटपुट –

उत्तर

1

SQL Fiddle

with v as (
    select 
     a.id as actor_id, 
     a.name as actor_name, 
     m.id as m_id 
    from 
     actor a 
     inner join 
     movie_brats mb on a.id = mb.actor_id 
     inner join 
     movie m on m.id = mb.movie_id 
) 
select 
    v1.actor_name as "Name", 
    string_agg(
     distinct v2.actor_name, ', ' order by v2.actor_name 
    ) as "Worked With" 
from 
    v v1 
    left join 
    v v2 on v1.m_id = v2.m_id and v1.actor_id != v2.actor_id 
group by 1 
order by 1 

अलग एकत्रीकरण ऊपर आवश्यक है बार-बार नाम मामले में वे एक से अधिक फिल्म में एक साथ काम किया नहीं दिखाने के लिए।

left join एक ऐसे अभिनेता को दबाने के लिए आवश्यक नहीं है जो किसी अन्य व्यक्ति के साथ inner join के साथ काम न करे।

आप दिखाना चाहते हैं जो फिल्म में वे एक साथ काम किया: SQL Fiddle

with v as (
    select 
     a.id as actor_id, 
     a.name as actor_name, 
     m.id as m_id, 
     m.title as title 
    from 
     actor a 
     inner join 
     movie_brats mb on a.id = mb.actor_id 
     inner join 
     movie m on m.id = mb.movie_id 
) 
select 
    a1 as "Name", 
    string_agg(
     format('%s (in %s)', a2, title), ', ' 
     order by format('%s (in %s)', a2, title) 
    ) as "Worked With" 
from (
    select 
     v1.actor_name as a1, 
     v2.actor_name as a2, 
     string_agg(v1.title, ', ' order by v1.title) as title  
    from 
     v v1 
     left join 
     v v2 on v1.m_id = v2.m_id and v1.actor_id != v2.actor_id 
    group by 1, 2 
) s 
group by 1 
order by 1 
+1

@ डॉवी मैंने स्पष्टीकरण के साथ प्रश्न अपडेट किया। –

1

आपकी क्वेरी की मुख्य समस्या यह है कि आप (क्रॉस) केवल movie_brats में शामिल हो जाते हैं, इसलिए प्रत्येक अभिनेता को प्रत्येक फिल्म (जहां वह खेला जाता है) द्वारा मुद्रित किया जाएगा - यह अधिक obvio है हम, यदि आप आंतरिक क्वेरी में उपयोग करने के लिए अपनी क्वेरी बदलते हैं (क्रॉस के बदले + where)।

सुझाव:

  • movie तालिका में शामिल होने की जरूरत नहीं है, जब तक आप
  • उपयोग distinct नकली नाम
  • a1.id <> a2.id द्वारा फिल्टर एक अभिनेता से बचने के लिए से बचने के लिए अभिनेता से सभी फिल्म शीर्षकों प्रिंट चाहते हैं सूचीबद्ध होने के रूप में वह खुद के साथ काम किया।

Here is एक काम उदाहरण:

select a1.name, string_agg(distinct a2.name, ', ') as co_names 
from actor a1 
inner join movie_brats mb1 on a1.id = mb1.actor_id 
inner join movie_brats mb2 on mb1.movie_id = mb2.movie_id 
inner join actor a2 on a2.id = mb2.actor_id 
where a1.id <> a2.id 
group by a1.id 
+1

@Dowwie के साथ दूसरी क्वेरी को अपडेट किया है, यदि आप अपने आप में शामिल नहीं हैं, तो आपके पास केवल पंक्तियां होंगी, जिनमें एक 'movie_id' और' actor_id' जोड़ी होगी। यदि आप इसे अपने खिलाफ जोड़ते हैं ('movie_id' फ़ील्ड का उपयोग करके) आपको सभी' अभिनेता_आईडी 'जोड़े के साथ परिणाम मिलेंगे, जहां' movie_id' समान है - केवल शुद्ध जुड़ने वाले तर्क। – pozs

संबंधित मुद्दे