MySQL到PostgreSQL的转换

时间:2011-06-26 05:40:27

标签: mysql postgresql database

我在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

4 个答案:

答案 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;