我使用的是Postgres 9.6,我有一个查询,该查询显示了包含特定字符串“ xyz”的前100行。大致如下所示:
SELECT name FROM data WHERE name ILIKE '%xyz%' ORDER BY other_column LIMIT 100;
我实际上想要实现的是将匹配的行放在name列开头的前面。因此总共仍然有100行,但是首先从与name ILIKE 'xyz%
匹配的结果中填充,然后再从ILIKE '%xyz%'
的结果中填充。
我试图通过UNION查询大致实现以下目标
SELECT name FROM data WHERE name ILIKE 'xyz%'
UNION
SELECT name FROM data WHERE name ILIKE '%xyz%'
ORDER BY other_column
LIMIT 100;
这显然不起作用,因为它是按other_column
排序的。我最初的想法是在每个查询中添加一列用于排序
SELECT 1 as sort_order, name FROM data WHERE name ILIKE 'xyz%'
UNION
SELECT 2 as sort_order, name FROM data WHERE name ILIKE '%xyz%'
ORDER BY sort_order, other_column
LIMIT 100;
但这会杀死UNION
的重复删除,而表现得像UNION ALL
,因为我通过添加sort_order列使原来相同的行有所不同。
我当然可以在数据库外的后续步骤中进行重复删除,但这对我来说并不是一个非常吸引人的解决方案。有什么方法可以分别对UNION查询的各个部分进行排序,并实现我描述的结果?
答案 0 :(得分:1)
使用函数position(substring in string)
代替UNION,例如:
WITH data(name, other_column) AS (
VALUES
('abc xyz', 1),
('xyz abc', 2),
('a xyz b', 3),
('xyz abc', 4)
)
SELECT name, other_column
FROM data
WHERE name ILIKE '%xyz%'
ORDER BY position('xyz' in name), other_column
LIMIT 100;
name | other_column
---------+--------------
xyz abc | 2
xyz abc | 4
a xyz b | 3
abc xyz | 1
(4 rows)
或:
SELECT name, other_column
FROM data
WHERE name ILIKE '%xyz%'
ORDER BY position('xyz' in name) > 1, other_column
LIMIT 100;
name | other_column
---------+--------------
xyz abc | 2
xyz abc | 4
abc xyz | 1
a xyz b | 3
(4 rows)
答案 1 :(得分:0)
通过使用other_column
:
SELECT t.name FROM (
SELECT name, CONCAT(' ', name) AS other_column FROM data WHERE (name ILIKE 'xyz%')
UNION
SELECT name, name AS other_column FROM data WHERE (name ILIKE '%xyz%') AND (name NOT ILIKE 'xyz%')
) AS t
ORDER BY t.other_column
LIMIT 100;
这是在第一个列表中的name
后面添加一个空格(ASCII 32)前缀并创建other_column
。
在第二个列表中,other_column
与name
相同。
最后按other_column
排序。