UNION-запрос, заказанный отдельно его компонентами - PullRequest
0 голосов
/ 21 ноября 2018

Я использую Postgres 9.6, и у меня есть запрос, который показывает первые 100 строк, которые содержат конкретную строку, в данном примере «xyz».Это выглядит примерно так:

SELECT name FROM data WHERE name ILIKE '%xyz%' ORDER BY other_column LIMIT 100;

Чего я на самом деле хочу добиться, так это поместить строки, совпадающие в начале столбца имени, впереди.Таким образом, всего 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 голосов
/ 21 ноября 2018

Используйте функцию 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)    
0 голосов
/ 21 ноября 2018

Используя 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;

, это добавляет префикс пробела (ASCII 32) к name в первом списке и создает other_column.Во втором списке other_column совпадает с name.Наконец сортирует по other_column.

...