我在MySQL编写了一个查询: -
SELECT * FROM `employees` WHERE ((first_name LIKE "s%" OR middle_name LIKE "s%" OR last_name LIKE "s%")) ORDER BY first_name ASC;
我试图在PostgreqSQL中执行此查询但是它会出现一个错误,表示列“s%”不存在。
之后我将单引号放在LIKE语句中而不是双qoutes。
SELECT * FROM `employees` WHERE ((first_name LIKE 's%' OR middle_name LIKE 's%' OR last_name LIKE 's%')) ORDER BY first_name ASC;
现在PostgreSQL执行该查询但它返回一个空集。 我正在使用postgreSQL 8.3
答案 0 :(得分:3)
第二个声明不在PostgreSQL中运行,因为员工的反复无效 - 但这可能是副本&粘贴错误。
如果您实际删除了那些可怕的反引号(在MySQL中甚至不需要),则很可能第二个语句没有返回任何值,因为PostgreSQL中的字符串比较区分大小写,并且您的列包含一个强大的S
而不是s
尝试:
SELECT *
FROM employees
WHERE ((lower(first_name) LIKE 's%' OR
lower(middle_name) LIKE 's%' OR
lower(last_name) LIKE 's%'))
ORDER BY first_name ASC;
答案 1 :(得分:1)
Postgres默认使用区分大小写的LIKE
语句,而MySQL默认为不区分大小写。
使用ILIKE
运算符获得与MySQL相同的行为。
答案 2 :(得分:1)
这是一个例子,我将使用生成的“名称”,这些名称实际上是数字,这应该是相同的......
请注意,如果您希望搜索忽略重音,就像MySQL一样,您需要将lower()替换为将重音符号转换为非重音符号的函数。由于该函数可能会很慢,因此最好实现列。
如果您希望LIKE使用索引,请不要忘记使用特殊索引类型text_pattern_ops!
create table test (a TEXT, b TEXT, c TEXT);
INSERT INTO test SELECT n, n*3, n*7 FROM generate_series( 1,100000 ) n;
create index test_a on test( lower( a ) text_pattern_ops );
create index test_b on test( lower( b ) text_pattern_ops );
create index test_c on test( lower( c ) text_pattern_ops );
EXPLAIN ANALYZE SELECT * FROM test WHERE lower(a) LIKE '12%' OR lower(b) LIKE '12%' OR lower(c) LIKE '12%' ORDER BY lower(a) LIMIT 10;
QUERY PLAN
----------------------------------------------------------------------------------------------------------------------------------------
Limit (cost=1081.12..1081.15 rows=10 width=17) (actual time=16.987..16.992 rows=10 loops=1)
-> Sort (cost=1081.12..1096.04 rows=5969 width=17) (actual time=16.986..16.986 rows=10 loops=1)
Sort Key: (lower(a))
Sort Method: top-N heapsort Memory: 25kB
-> Bitmap Heap Scan on test (cost=144.68..952.13 rows=5969 width=17) (actual time=1.107..13.261 rows=6405 loops=1)
Recheck Cond: ((lower(a) ~~ '12%'::text) OR (lower(b) ~~ '12%'::text) OR (lower(c) ~~ '12%'::text))
Filter: ((lower(a) ~~ '12%'::text) OR (lower(b) ~~ '12%'::text) OR (lower(c) ~~ '12%'::text))
-> BitmapOr (cost=144.68..144.68 rows=6341 width=0) (actual time=1.081..1.081 rows=0 loops=1)
-> Bitmap Index Scan on test_a (cost=0.00..22.95 rows=1068 width=0) (actual time=0.210..0.210 rows=1111 loops=1)
Index Cond: ((lower(a) ~>=~ '12'::text) AND (lower(a) ~<~ '13'::text))
-> Bitmap Index Scan on test_b (cost=0.00..81.85 rows=3758 width=0) (actual time=0.603..0.603 rows=3707 loops=1)
Index Cond: ((lower(b) ~>=~ '12'::text) AND (lower(b) ~<~ '13'::text))
-> Bitmap Index Scan on test_c (cost=0.00..35.42 rows=1515 width=0) (actual time=0.266..0.266 rows=1587 loops=1)
Index Cond: ((lower(c) ~>=~ '12'::text) AND (lower(c) ~<~ '13'::text))
Total runtime: 17.038 ms
这里的OR变成了位图-OR索引扫描,速度非常快。注意,使用前两个“字母”,其选择性为1%。如果你只使用一个字母,你可能会得到相当低的选择性和一个不太可能有用的巨大结果列表,所以最好等到用户输入2个字符然后启动自动完成。
使用UNION并不快。
但还有另一个黑客!看:
select * from (values ('a'),('b'),('A'),('Â')) foo where column1 >= 'a' AND column1 < 'b';
column1
---------
a
A
Â
确定...
create index test_aa on test( a );
create index test_ba on test( b );
create index test_ca on test( c );
在这里你需要取用户输入的字符串(例如,'no'),删除重音和小写,并递增最后一个字符(这给你'np')。所有以'no'开头的名称都具有名称&gt; ='no'且名称&lt; 'np',因为整理规则,它包含重音符。
EXPLAIN ANALYZE
SELECT * FROM (SELECT * FROM test WHERE a >= '12' AND a < '13' ORDER BY a LIMIT 10) f1
UNION
SELECT * FROM (SELECT * FROM test WHERE b >= '12' AND b < '13' ORDER BY b LIMIT 10) f2
UNION
SELECT * FROM (SELECT * FROM test WHERE c >= '12' AND c < '13' ORDER BY c LIMIT 10) f3
ORDER BY a;
QUERY PLAN
----------------------------------------------------------------------------------------------------------------------------------------------
Sort (cost=27.20..27.27 rows=30 width=96) (actual time=0.451..0.456 rows=30 loops=1)
Sort Key: public.test.a
Sort Method: quicksort Memory: 27kB
-> HashAggregate (cost=26.16..26.46 rows=30 width=96) (actual time=0.399..0.404 rows=30 loops=1)
-> Append (cost=0.00..25.94 rows=30 width=96) (actual time=0.157..0.372 rows=30 loops=1)
-> Limit (cost=0.00..7.35 rows=10 width=17) (actual time=0.157..0.163 rows=10 loops=1)
-> Index Scan using test_aa on test (cost=0.00..784.85 rows=1068 width=17) (actual time=0.156..0.161 rows=10 loops=1)
Index Cond: ((a >= '12'::text) AND (a < '13'::text))
-> Limit (cost=0.00..6.96 rows=10 width=17) (actual time=0.122..0.133 rows=10 loops=1)
-> Index Scan using test_ba on test (cost=0.00..2614.31 rows=3758 width=17) (actual time=0.122..0.131 rows=10 loops=1)
Index Cond: ((b >= '12'::text) AND (b < '13'::text))
-> Limit (cost=0.00..11.03 rows=10 width=17) (actual time=0.066..0.072 rows=10 loops=1)
-> Index Scan using test_ca on test (cost=0.00..1671.03 rows=1515 width=17) (actual time=0.066..0.070 rows=10 loops=1)
Index Cond: ((c >= '12'::text) AND (c < '13'::text))
Total runtime: 0.527 ms
这更快,更快,并且它有一些非常有用的属性。
由于删除了排序并使用了索引扫描(因为LIMIT 10),因此查询在所有情况下都非常快。它只是没有返回所有结果。
如果用户搜索“a%”等名称并获得5000个结果,则此结果对用户无效,相反,他只需添加一个字母即可进行更精确的查询。因此,用于计算和返回5000个结果所花费的数据库资源是无用的。最好像这样快速,有界时间查询并显示“更多结果......”,这样用户就知道他应该在搜索框中输入更多字母。
答案 3 :(得分:0)
尽量避免在SQL中使用OR语句。选择将是:
SELECT * FROM ((SELECT * FROM employees WHERE first_name LIKE 's%') UNION (SELECT * FROM employees WHERE middle_name LIKE 's%') UNION (SELECT * FROM employees WHERE last_name LIKE 's%')) AS foo ORDER BY first_name;