使用Django ORM执行复杂的自引用查询

时间:2012-09-12 15:41:12

标签: sql django orm

我有以下型号:

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

使用示例数据:

| url | email           | contacted |
+-----+-----------------+-----------+
| foo | foo@example.com | N         |
| bar | bar@example.com | N         |
| baz | foo@example.com | Y         |

我想选择从未联系过电子邮件地址的所有不同行(通过电子邮件地址)。使用此示例数据,bar@example.com行将是唯一返回的行。

2 个答案:

答案 0 :(得分: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 )
    )

请注意,对于许多记录而言,此查询可能不是最佳记录,但它可能适用于大多数用途。

答案 1 :(得分: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', 'foo@example.com', False)
,( 'bar', 'bar@example.com', False)
,( 'baz', 'foo@example.com', 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
        ) ;