我在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
:
到目前为止,我得到了这个:
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);
它可以工作,但在我看来像是一个黑客,我也不知道随着数据库的增长这个查询的性能。 我的问题是,有没有更好的方法来做到这一点。
答案 0 :(得分:3)
编辑:我稍微修改了逻辑,我认为它符合您的要求
以下代码将在两个条件下返回1
...
user
和mac
0
行,0
mac
行
在所有其他条件下,查询返回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'
答案 1 :(得分: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)
上为第三个添加索引。
答案 2 :(得分:0)
实际上,当涉及OR
时,所有数据库都不会使用索引,因此请避免使用连接中的索引。
您似乎真的在进行两个单独的查询:
所以联合不会像子选择集合那么容易。使用单独的查询将信息拆分为自己的简单查询,并将它们合并为一个:
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
如果当前没有分配任何内容,则两列都可能为空,否则它们将显示为每个关注点分配的内容。