左外连接 - 如何在第二个表中返回一个布尔值?

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 的列,其中包含 truefalse

所以我正在尝试左外连接查询:

# 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 值而不是字符串?

我不是在寻找coalescecase的表达方式,而是在寻找“正确”的方式来进行这样的查询。

【问题讨论】:

【参考方案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

以上是关于左外连接 - 如何在第二个表中返回一个布尔值?的主要内容,如果未能解决你的问题,请参考以下文章

HQL 左外连接用于查找一个表中存在而其他表中不存在的记录

使用 LINQ 查询语法 EF Core C# 的左外连接

左外连接代码的不明确列名

netezza 左外连接查询性能

左外连接和右外连接的区别

oracle 左外连接如果右表中有重复数据如何处理?