2012-09-12 25 views
4

一個複雜的自引用查詢我有以下模式:執行使用Django的ORM

class Message(Model): 
    url = URLField("URL") 
    email = EmailField("E-Mail") 
    contacted = BooleanField("Contacted", default=False) 

有了這樣的示例數據:

| url | email   | contacted | 
+-----+-----------------+-----------+ 
| foo | [email protected] | N   | 
| bar | [email protected] | N   | 
| baz | [email protected] | Y   | 

我想選擇所有不同行(通過e電子郵件地址)的電子郵件地址從未聯繫過。使用此示例數據,[email protected]行將是唯一返回的行。

+0

爲什麼[email protected]是唯一返回的?由於[email protected]已聯繫設置爲False,並且是明顯的。 – thikonom

+0

@thikonom如果曾經聯繫過電子郵件地址,則不應將其包含在結果中。這是問題的根源。 ;) – amcgregor

+0

我不知道django,但在sql中這幾乎是微不足道的。 – wildplasser

回答

2

這將返回所需的記錄:

not_contacted = Message.objects.exclude(
    email__in=Message.objects.filter(contacted=True).values('email') 
) 

這有隻運行一個查詢的優勢。您的查詢會是這個樣子:

SELECT 
    messages_message.id, messages_message.url, messages_message.email, messages_message.contacted 
FROM 
    Messages 
WHERE NOT 
    (messages_message.email IN 
     (SELECT U0.email from messages_message U0 WHERE U0.contacted = True) 
    ) 

注意,對於許多人來說,多條記錄此查詢可能不是最優的,但它可能對大多數應用工作。

+0

Huzzah!謝謝!這是@ wildplasser的純SQL解決方案的Django版本。希望我能接受兩者。 :d – amcgregor

1
DROP SCHEMA tmp CASCADE; 
CREATE SCHEMA tmp ; 
SET search_path=tmp; 

CREATE TABLE massage 
     (zurl varchar NOT NULL 
     , zemail varchar NOT NULL 
     , contacted boolean 
     ); 
INSERT into massage(zurl, zemail, contacted) VALUES 

('foo', '[email protected]', False) 
,('bar', '[email protected]', False) 
,('baz', '[email protected]', True) 
     ; 

SELECT 
     DISTINCT zemail AS zemail 
     , MIN(zurl) AS zurl 
FROM massage m 
WHERE NOT EXISTS (
     SELECT * 
     FROM massage nx 
     WHERE nx.zemail = m.zemail 
     AND nx.contacted = True 
     ) 
GROUP BY zemail; 

如果給定電子郵件地址有多個記錄,則上面那個選擇具有「最低」URL的記錄。如果你希望他們所有的查詢會更簡單:

SELECT m.zurl, m.zemail 
FROM massage m 
WHERE NOT EXISTS (
     SELECT * 
     FROM massage nx 
     WHERE nx.zemail = m.zemail 
     AND nx.contacted = True 
     ) ;