2010-08-29 29 views
0

這是我的問題。假設我有一個名爲persons的表格,其中包含人名和國家標識號的字段,其中後者是可選的。每個實際的人可以有多行。PostgreSQL:用於確定不同行的自定義邏輯?

現在假設我想爲每個實際的人選擇一行。對於應用程序而言,如果a)它們的ID號匹配,或者b)它們的名稱匹配且一個或兩個的ID號爲NULL,則認爲兩行是指同一個人。 SELECT DISTINCT在這裏不好:我不能做DISTINCT ON (name, id),因爲那麼兩個具有相同名稱且ID爲1的行不匹配(這是不正確的,它們應該被認爲是相同的)。我不能做一個DISTINCT ON (name),因爲然後具有相同名稱但不同ID的行將匹配(再次不正確,它們應該被認爲是不同的)。我不能做DISTINCT ON (id),因爲那麼ID爲NULL的所有行都被認爲是相同的(顯然不正確)。

有什麼辦法可以重新定義PostgreSQL比較行的方式來判斷它們是否相同?我猜DISTINCT ON (name, id)的默認行爲應該是IF a.name = b.name AND a.id = b.id THEN IDENTICAL ELSE DISTINCT。我想重新定義它,如IF a.id = b.id OR (a.name = b.name AND (a.id IS NULL OR b.id IS NULL)) THEN IDENTICAL ELSE DISTINCT

這很晚了,我可能錯過了一些明顯的東西,所以關於如何實現我想要的其他建議也是受歡迎的。任何使我能夠根據比簡單的列列表更復雜的標準來選擇不同的行。提前致謝。

回答

1

有窗函數

-- 
-- First, SELECT those names with NULL national IDs not shadowed by the same 
-- name with a national ID. Each one is a unique person. 
-- 
SELECT name, id 
FROM persons 
WHERE NOT EXISTS (SELECT 1 
        FROM persons p 
        WHERE p.name = persons.name AND p.id IS NOT NULL) 
-- 
-- Second, collapse each national ID into the "first" row with that ID, 
-- whatever the name. Each ID is a unique person. 
-- 
UNION ALL 
SELECT name, id 
    FROM (SELECT name, id, ROW_NUMBER() OVER (PARTITION BY id) 
      FROM persons 
     WHERE id IS NOT NULL) d 
WHERE d.row_number = 1; 

沒有窗口功能

更換上述UNIONGROUP BY第一(MIN())名稱爲每個非空ID:

... 
UNION ALL 
    SELECT MIN(name) AS name, id 
    FROM persons 
    WHERE id IS NOT NULL 
GROUP BY id 
+0

感謝您的建議。但是,我在PostgreSQL 8.1上,AFAIK沒有窗口函數。 – Indrek 2010-08-29 13:55:42

+0

不要以爲你需要的窗口功能: ... UNION ALL 選擇不同的名稱,從人 其中id是不是空 – Corey 2010-08-29 14:24:26

+0

@Corey ID,即以下對'失敗(姓名,身份證)代表同一個人的元組* *:'('Bob Jones',123)','('Robert A. Jones',123)'。 – pilcrow 2010-08-29 15:23:42

0

它似乎是主要問題是您的數據庫的佈局。我不知道你的具體應用程序的細節,但對同一個人有多行和空ID通常是一個壞主意。如果可能的話,您可能需要考慮爲需要多行的信息創建單獨的表,其中persons只包含每人一行和每行唯一標識符。

但是,如果你不能這樣做...我不認爲只有一個獨特的人會解決這個問題。

什麼的問題:

select distinct name, id 
from persons 
where id is not null 

你有一些人有一個名稱,但不是一個ID?或者您是否需要其他行的某些特定數據?

以下是另一個問題:如果有兩行具有相同名稱和空ID,並且具有相同名稱和不同ID的多個人,那麼如何知道空行匹配哪個人?

+0

是,則數據庫結構不是最優的,而且我實際上正在改變它。像您所描述的那樣,「人」表包含每人一行,但要做到這一點,我需要一種方法將所有現有行壓縮爲一行。因此,這個問題。 是的,我有人有一個名字,但沒有一個ID。就像我上面所說的那樣,ID字段是可選的。否則,我只是'選擇DISTINCT ON(ID)'。 – Indrek 2010-08-29 13:31:21

+0

「這是另一個問題:如果有兩行具有相同名稱和空ID,並且具有相同名稱和不同ID的多個人,那麼您如何知道空行匹配哪個人? 沒有這樣的行存在,所以這是一個模擬問題。 – Indrek 2010-08-29 13:41:40