UNION查询按其组件分别排序

时间:2018-11-21 17:23:52

标签: sql postgresql union

我使用的是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查询的各个部分进行排序,并实现我描述的结果?

2 个答案:

答案 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_columnname相同。
最后按other_column排序。