2014-07-03 214 views
3

我有以下數據庫:如何在使用子查詢時使用連接來消除笛卡爾積?

paperid | authorid | name 
---------+----------+--------------- 
1889374 | 897449 | D. N. Page 
1889374 | 1795881 | C. N. Pope 
1889374 | 1952069 | S. W. Hawking 

我想創建具有下列的表:

  • paperid
  • 作者姓名 - 此paperid
  • 合作者的每個作者 - 對於該紙張的每個共同作者

結果s HOULD這個樣子的:

paperid | author  |   coauthors   
---------+---------------+--------------------------- 
1889374 | D. N. Page | C. N. Pope S. W. Hawking 
1889374 | C. N. Pope | D. N. Page S. W. Hawking 
1889374 | S. W. Hawking | D. N. Page C. N. Pope 

,這與下面的查詢來實現:

SELECT foo.paperid, npa.name as author, foo.coauthors 
INTO npatest 
FROM newpaperauthor npa 
CROSS JOIN (
    SELECT paperid, string_agg(name, ' ') as coauthors 
    FROM newpaperauthor 
    GROUP BY paperid 
    ORDER BY paperid) foo; 
UPDATE npatest SET coauthors = regexp_replace(coauthors, author, ''); 
SELECT * FROM npatest; 

的問題出現時,有更多的paperid S IN數據庫喜歡:

paperid | authorid |  name  |  affiliation  
---------+----------+------------------+------------------------ 
1889373 | 122817 | Kazuhiro Hongo | 
1889373 | 1091191 | Hiroshi NAKAGAWA | 
1889373 | 1874415 | Hiroshi Nakagawa | University of Oklahoma 
1889373 | 2149773 | Han Soo Chang | 
1889374 | 897449 | D. N. Page  | 
1889374 | 1795881 | C. N. Pope  | 
1889374 | 1952069 | S. W. Hawking | 

然後我會得到像他們這樣的笛卡爾產品:

paperid |  author  |       coauthors        
---------+------------------+---------------------------------------------------------------- 
1889373 | Kazuhiro Hongo | Hiroshi NAKAGAWA Hiroshi Nakagawa Han Soo Chang 
1889374 | Kazuhiro Hongo | D. N. Page C. N. Pope S. W. Hawking 
1889373 | Hiroshi NAKAGAWA | Kazuhiro Hongo Hiroshi Nakagawa Han Soo Chang 
1889374 | Hiroshi NAKAGAWA | D. N. Page C. N. Pope S. W. Hawking 
1889373 | Hiroshi Nakagawa | Kazuhiro Hongo Hiroshi NAKAGAWA Han Soo Chang 
1889374 | Hiroshi Nakagawa | D. N. Page C. N. Pope S. W. Hawking 
1889373 | Han Soo Chang | Kazuhiro Hongo Hiroshi NAKAGAWA Hiroshi Nakagawa 
1889374 | Han Soo Chang | D. N. Page C. N. Pope S. W. Hawking 
1889373 | D. N. Page  | Kazuhiro Hongo Hiroshi NAKAGAWA Hiroshi Nakagawa Han Soo Chang 
1889374 | D. N. Page  | C. N. Pope S. W. Hawking 
1889373 | C. N. Pope  | Kazuhiro Hongo Hiroshi NAKAGAWA Hiroshi Nakagawa Han Soo Chang 
1889374 | C. N. Pope  | D. N. Page S. W. Hawking 
1889373 | S. W. Hawking | Kazuhiro Hongo Hiroshi NAKAGAWA Hiroshi Nakagawa Han Soo Chang 
1889374 | S. W. Hawking | D. N. Page C. N. Pope 

如何擺脫那裏的笛卡爾產品?

+0

你想在任何特定的方式合作者排序? –

+0

@ErwinBrandstetter不是真的,這對我無所謂。 – Patryk

回答

2

這可以是令人驚訝的簡單array_agg()作爲窗口集合函數array_remove()(帶PG 9.3引入)合併:

CREATE TABLE npatest AS 
SELECT paperid, name AS author 
    , array_to_string(array_remove(array_agg(name) OVER (PARTITION BY paperid), name), ', ') AS coauthors 
FROM newpaperauthor n; 

如果作者姓名是不是唯一的,有併發症。
然後,如果作者姓名不唯一,那麼您的整個操作都是有缺陷的。

使用array_agg()array_remove()代替string_agg()regexp_replace(),因爲後者很容易失敗,對於像「喬恩狐狸」和「喬恩狡猾」相似的名字,也凌亂帶分隔符。

array_to_string()將數組轉換爲字符串。我用', '作爲分隔符,這對我來說似乎比只是一個空間更明智。

不鼓勵使用SELECT INTO。改爲使用高級CREATE TABLE ASPer documentation:

CREATE TABLE AS是推薦的語法,因爲這種形式的 SELECT INTO是不是在ECPG或者PL/pgSQL中使用,因爲它們 不同的方式解釋了INTO條款。此外,CREATE TABLE AS 提供SELECT INTO提供的功能的超集。

SQL Fiddle.

+0

您的查詢非常簡單,但它返回JSON數組格式的共同作者:'1 | Mahmoud Refaat | {「Motaz Ahmad El-saban」,「Ayman Kaheel」,「Ahmed Abdul-hamid」} – Patryk

+0

@Patryk:這不是JSON格式,而是數組的Postgres文本表示。我留下說明如何使用'array_to_string()'轉換爲文本。現在拼出來。 –

3

這裏是解決這個問題的方法:

生成所有共同作者作爲一個子查詢的列表。生成所有作者的列表。然後將它們連接在一起,並進行字符串操作以獲得所需內容。


作者很簡單:

select paperid, npa.name as author 
from newpaperauthor npa; 

的合着者很容易:

select paperid, string_agg(npa.name, ' ') as coauthors 
from newpaperauthor npa 
group by paperid; 

的組合需要一些名單替代:

select a.paperid, a.author, 
     replace(replace(coauthors, author, ''), ' ', ' ') as coauthors 
from (select paperid, npa.name as author 
     from newpaperauthor npa 
    ) a join 
    (select paperid, string_agg(npa.name, ' ') as coauthors 
     from newpaperauthor npa 
     group by paperid 
    ) ca 
    on a.paperid = ca.paperid; 
+0

我不得不將最後一行改爲'on a.paperid = ca.paperid;',因爲它給了我'JOIN/ON的參數必須是類型布爾值,而不是輸入bigint'。謝謝:) – Patryk

+0

@Patryk。 。 。這是一個錯字。感謝您修復它。 –

0

@GordonLinoff「 s的查詢可以簡化一下b ÿ抑制第一作者在總量:

SELECT DISTINCT 
     p0.paperid , p0.authorid , p0.name as name1 
     , string_agg(p1.name, ', ') AS others 
FROM papers p0 
JOIN papers p1 ON p1.paperid = p0.paperid AND p1.authorid <> p0.authorid 
GROUP BY p0.paperid, p0.authorid, p0.name 
ORDER BY p0.paperid, p0.authorid 
     ;