PostgreSQL是否有简单的大小写比较?

我想替换:

SELECT id, user_name 
    FROM users 
        WHERE lower(email) IN (lower('adamB@a.com'), lower('eveA@b.com'));

比如:

SELECT id, user_name 
    FROM users 
        WHERE email IGNORE_CASE_IN ('adamB@a.com', 'eveA@b.com');

likeilike运算符处理单个值(例如like 'adamB@a.com'),但不处理集合.

推荐答案

首先,不要做什么:don't use 100...

create table y
(
id serial not null,
email text not null unique
);

insert into y(email) 
values('iSteve.jobs@apple.com') ,('linus.Torvalds@linUX.com');
insert into y(email) 
select n from generate_series(1,1000) as i(n);

-- no need to create an index on email, 
-- UNIQUE constraint on email already makes an index.
-- thanks a_horse_with_no_name
-- create index ix_y on y(email);

explain select * from y 
where email ilike 
    ANY(ARRAY['ISteve.Jobs@Apple.com','Linus.Torvalds@Linux.com']);

执行计划:

memdb=# explain select * from y where email ilike ANY(ARRAY['ISteve.Jobs@Apple.com','Linus.Torvalds@Linux.com']);
                                       QUERY PLAN                                       
----------------------------------------------------------------------------------------
 Seq Scan on y  (cost=0.00..17.52 rows=1 width=7)
   Filter: (email ~~* ANY ('{ISteve.Jobs@Apple.com,Linus.Torvalds@Linux.com}'::text[]))
(2 rows)

要么你创建一个索引较低的表达式...

create function lower(t text[]) returns text[]
as
$$
select lower($1::text)::text[]
$$ language sql;

create unique index ix_y_2 on y(lower(email));

explain select * from y 
where lower(email) = 
    ANY(lower(ARRAY['ISteve.Jobs@Apple.com','Linus.Torvalds@Linux.com']));

...正确使用索引:

memdb=# explain select * from y where lower(email) = ANY(lower(ARRAY['ISteve.Jobs@Apple.com','Linus.Torvalds@Linux.com']));
                                                           QUERY PLAN                                                           
--------------------------------------------------------------------------------------------------------------------------------
 Bitmap Heap Scan on y  (cost=22.60..27.98 rows=10 width=7)
   Recheck Cond: (lower(email) = ANY ((lower(('{ISteve.Jobs@Apple.com,Linus.Torvalds@Linux.com}'::text[])::text))::text[]))
   ->  Bitmap Index Scan on ix_y_2  (cost=0.00..22.60 rows=10 width=0)
         Index Cond: (lower(email) = ANY ((lower(('{ISteve.Jobs@Apple.com,Linus.Torvalds@Linux.com}'::text[])::text))::text[]))
(4 rows)

或者使用citext数据类型...

create table x
(
id serial not null,
email citext not null unique
);

insert into x(email) 
values('iSteve.jobs@apple.com'),('linus.Torvalds@linUX.com');
insert into x(email) 
select n from generate_series(1,1000) as i(n);

-- no need to create an index on email, 
-- UNIQUE constraint on email already makes an index.
-- thanks a_horse_with_no_name
-- create index ix_x on x(email);

explain select * from x 
where email = 
ANY(ARRAY['ISteve.Jobs@Apple.com','Linus.Torvalds@Linux.com']::citext[]);

...哪怕您没有在表达式上创建索引,它也会正确使用索引(例如,在yyy(下(字段))上创建索引zzz):

memdb=# explain select * from x where email = ANY(ARRAY['ISteve.Jobs@Apple.com','Linus.Torvalds@Linux.com']::citext[]);
                                            QUERY PLAN                                            
--------------------------------------------------------------------------------------------------
Bitmap Heap Scan on x  (cost=8.57..13.91 rows=2 width=36)
  Recheck Cond: (email = ANY ('{ISteve.Jobs@Apple.com,Linus.Torvalds@Linux.com}'::citext[]))
  ->  Bitmap Index Scan on x_email_key  (cost=0.00..8.57 rows=2 width=0)
        Index Cond: (email = ANY ('{ISteve.Jobs@Apple.com,Linus.Torvalds@Linux.com}'::citext[]))

如果尚未安装citext字段类型,请运行以下命令:

CREATE EXTENSION IF NOT EXISTS citext WITH SCHEMA public;

Sql相关问答推荐

为什么Postgrs Planner会在输出部分中显示我在查询中不使用的列?'""

SQL(PostgreSQL)从条件创建点表

Oracle SQL-将结果列在单行中

如何从JSON数组中 Select 多个值

SQL SELECT MOST NEST TIMESTAMP BEAT ORDER

更新其组的日期字段值小于最大日期减go 天数的记录

在数据库中搜索列

PostgreSQL抽奖查询

PostgreSQL:按小时查看调整日期

我可以在SQL的IN子句中使用比子查询包含的值更少的值吗?

数据库SQL PARSE_SYNTAX_ERROR

属于(日期)范围类型及其交集的总权重​

将用户授予另一个用户不授予权限

为什么SQL in中的空子查询有时被视为null

将SQL Server查询改进为;线程安全;

具有多个表 JOINS 的 STRING_AGG 的替代方法 (SQL Server 2016)

如何为 ActiveRecord 联接应用附加条件

使用 regexp_replace 替换所有出现的特殊字符

如何对 SQL 表中的连续时间戳进行分组?

在 PostgreSQL 中,如何将数组中的每个元素用作另一个表中的键?