左外连接 - 如何在第二个表中返回一个布尔值?
Posted
技术标签:
【中文标题】左外连接 - 如何在第二个表中返回一个布尔值?【英文标题】:Left outer join - how to return a boolean for existence in the second table? 【发布时间】:2015-01-19 22:01:19 【问题描述】:在 CentOS 6 上的 PostgreSQL 9 中,pref_users
表中有 60000 条记录:
# \d pref_users
Table "public.pref_users"
Column | Type | Modifiers
------------+-----------------------------+--------------------
id | character varying(32) | not null
first_name | character varying(64) | not null
last_name | character varying(64) |
login | timestamp without time zone | default now()
last_ip | inet |
(... more columns skipped...)
另外一张桌子有大约 500 个不被允许玩的用户 id:
# \d pref_ban2
Table "public.pref_ban2"
Column | Type | Modifiers
------------+-----------------------------+---------------
id | character varying(32) | not null
first_name | character varying(64) |
last_name | character varying(64) |
city | character varying(64) |
last_ip | inet |
reason | character varying(128) |
created | timestamp without time zone | default now()
Indexes:
"pref_ban2_pkey" PRIMARY KEY, btree (id)
在 php 脚本中,我试图在 jQuery-dataTable 中显示来自 pref_users
的所有 60000 个用户。我想标记被禁止的用户(在pref_ban2
中找到的用户)。
这意味着我的查询中的每条记录都需要一个名为 ban
的列,其中包含 true
或 false
。
所以我正在尝试左外连接查询:
# select
b.id, -- how to make this column a boolean?
u.id,
u.first_name,
u.last_name,
u.city,
u.last_ip,
to_char(u.login, 'DD.MM.YYYY') as day
from pref_users u left outer join pref_ban2 b on u.id=b.id
limit 10;
id | id | first_name | last_name | city | last_ip | day
----+----------+-------------+-----------+-------------+-----------------+------------
| DE1 | Alex | | Bochum | 2.206.0.224 | 21.11.2014
| DE100032 | Княжна Мэри | | London | 151.50.61.131 | 01.02.2014
| DE10011 | Aлександр Ш | | Симферополь | 37.57.108.13 | 01.01.2014
| DE10016 | Semen10 | | usa | 69.123.171.15 | 25.06.2014
| DE10018 | Горловка | | Горловка | 178.216.97.214 | 25.09.2011
| DE10019 | -Дмитрий- | | пермь | 5.140.81.95 | 21.11.2014
| DE10047 | Василий | | Cумы | 95.132.42.185 | 25.07.2014
| DE10054 | Maedhros | | Чикаго | 207.246.176.110 | 26.06.2014
| DE10062 | ssergw | | москва | 46.188.125.206 | 12.09.2014
| DE10086 | Вадим | | Тула | 109.111.26.176 | 26.02.2012
(10 rows)
如您所见,上面的 b.id
列是空的 - 因为这 10 个用户没有被禁止。
如何在该列中获取false
值而不是字符串?
我不是在寻找coalesce
或case
的表达方式,而是在寻找“正确”的方式来进行这样的查询。
【问题讨论】:
【参考方案1】:“IS NULL”和“IS NOT NULL”返回一个布尔值,所以这应该很容易。
我想这就是你所需要的?
SELECT
b.id IS NOT NULL as is_banned, -- The value of "is_banned" will be a boolean
不确定您是否需要“NOT”,但无论哪种方式,您都会得到一个布尔值。
【讨论】:
【参考方案2】:带有外连接的 CASE 或 COALESCE 语句是执行此操作的正确方法。
select
CASE
WHEN b.id IS NULL THEN true
ELSE false
END AS banned,
u.id,
u.first_name,
u.last_name,
u.city,
u.last_ip,
to_char(u.login, 'DD.MM.YYYY') as day
from pref_users u
left outer join pref_ban2 b
on u.id=b.id
limit 10;
【讨论】:
感谢您的回答,但我不应该更好(更有效)在这里使用exists
吗?
所以EXISTS
充当过滤器。如果您使用EXISTS
,如果它被过滤掉,您将无法获得记录。如果要显示boolean
值,最好使用CASE
。
至此,您可以使用EXISTS
而不是OUTER JOIN
,但这不会改变布尔逻辑。
我是不是误会了什么?但是“IS NULL”和“IS NOT NULL”已经返回一个布尔值,那么 CASE WHEN 真的需要吗?你不能只选择列:“b.id IS NOT NULL as ban”
case
可以简化为b.id IS NULL
以上是关于左外连接 - 如何在第二个表中返回一个布尔值?的主要内容,如果未能解决你的问题,请参考以下文章