2

我在 PostgreSQL 数据库中有下表:

CREATE TABLE maclist (
    username character varying,
    mac macaddr NOT NULL,
    CONSTRAINT maclist_user_mac_key UNIQUE (username, mac)
);

我需要一种方法来检查 MAC 地址是否已分配给用户,或者用户根本没有分配 MAC 地址。基本上我需要一个查询,如果所有条件都为真或没有条件为真,即不是 XOR b ,则返回行。

编辑: 示例:

username | mac
john     | 11:22:33:44:55:66
john     | 11:22:33:44:55:67
doe      | 11:22:33:44:55:68

如果我查询:

username = john, mac = 11:22:33:44:55:66                     -> true, 1 whatever...
username = john, mac != 11:22:33:44:55:66                    -> 0, null or nothing...
username = jane, mac = no matter what except john's or doe's -> true, 1 whatever...
username = jane, mac = john's or doe's                       ->  0, null or nothing...

我需要true在两个条件下:

  1. 该(用户,mac)组合有一行。没有行
  2. 对于该用户并且该 mac 没有行

到目前为止,我得到了这个:

SELECT yes
FROM
  (SELECT 1 AS yes) AS dummy
LEFT JOIN maclist ON (username = 'user'
                      OR mac = '11:22:33:44:55:66')
WHERE ((username = 'user'
        AND mac = '11:22:33:44:55:66')
       OR (username IS NULL
           AND mac IS NULL);

它可以工作,但在我看来就像一个 hack,而且随着数据库的增长,我也不知道这个查询的性能。我的问题是是否有更好的方法来做到这一点。

4

3 回答 3

3

编辑:我稍微修改了逻辑,我认为它符合你想要的

以下代码将1在两种情况下返回...

  • user那和那有一排mac
  • 该用户有行0,该用户0mac

在所有其他条件下,查询返回0

  • 有行,user但没有一个行mac
  • 有行,mac 但没有一个行user


SELECT
  CASE WHEN COUNT(*) = 0                                THEN 1
       WHEN SUM(CASE WHEN mac = '11:22:33:44:55:66'
                      AND user = 'user' THEN 1
                                        ELSE 0 END) = 1 THEN 1
                                                        ELSE 0
  END
FROM
  maclist
WHERE
     username = 'user'
  OR mac      = '11:22:33:44:55:66'
于 2012-11-21T09:29:49.097 回答
1

您可以将查询简单地编写为:

prepare query_mac(text, macaddr) as
select exists (select 1 from maclist where username = $1 and mac = $2)
       or (not exists (select 1 from maclist where username = $1)
           and not exists (select 1 from maclist where mac = $2)
          );

PostgreSQL 将分别评估三个查询中的每一个,(username,mac)并对前两个使用唯一索引。如果需要,可以(mac)为第三个添加索引。

于 2012-11-21T11:04:30.903 回答
0

实际上,当涉及到时,所有数据库都不会使用索引OR,因此请避免连接中的那些。

编辑:

看来您确实在进行两个单独的查询:

  • 谁是分配给的mac(如果有)
  • 分配给用户的 mac(如果有)

所以联合不会像子选择的集合那么容易。使用单独的查询将信息拆分为他们自己的简单查询,并将它们组合成一个:

select
    (select username from maclist
     where mac = '11.22:33:44:55:66') as mac_assigned_to,
    (select mac from maclist
     where username = 'user') as user_assigned_to

如果当前没有分配任何内容,则这两列可能都有空值,否则它们将显示为每个关注点分配的内容。

于 2012-11-21T09:39:35.597 回答