Используя объединение и порядок по предложению в MySQL - PullRequest
112 голосов
/ 20 августа 2010

Я хочу использовать order by с объединением в запросе mysql. Я выбираю различные типы записей на основе разных критериев из таблицы, основанной на расстоянии для поиска на моем сайте. Первый запрос на выборку возвращает данные, относящиеся к точному поиску места. Второй запрос на выборку возвращает данные о расстоянии в пределах 5 км от искомого места. Третий запрос выбора возвращает данные о расстоянии в пределах 5-15 км от искомого места.

Затем я использую объединение, чтобы объединить все результаты и показать на странице с подкачкой. Под соответствующим заголовком как 'Точные результаты поиска' , 'Результаты в течение 5 км' и т. Д.

Теперь я хочу отсортировать результаты по идентификатору или дате добавления. Но когда я добавляю порядок по предложению в конце моего запроса (запрос 1 объединение запрос 2 объединение запрос 3 порядок по add_date). Сортирует все результаты. Но то, что я хочу, это сортировать по каждому заголовку.

Ответы [ 10 ]

204 голосов
/ 20 августа 2010

Вы можете сделать это, добавив псевдостолбец с именем rank к каждому выбранному элементу, который вы можете отсортировать сначала, перед сортировкой по другим критериям, например ::

select *
from (
    select 1 as Rank, id, add_date from Table 
    union all
    select 2 as Rank, id, add_date from Table where distance < 5
    union all
    select 3 as Rank, id, add_date from Table where distance between 5 and 15
) a
order by rank, id, add_date desc
40 голосов
/ 20 августа 2010

Для этого можно использовать подзапросы:

select * from (select values1 from table1 order by orderby1) as a
union all
select * from (select values2 from table2 order by orderby2) as b
25 голосов
/ 30 ноября 2011
(select add_date,col2 from table_name) 
  union 
(select add_date,col2 from table_name) 
  union 
(select add_date,col2 from table_name) 

order by add_date
8 голосов
/ 29 сентября 2015

Не забывайте, объединение всех - это способ добавления записей в набор записей без сортировки или объединения (в отличие от объединения).

Так, например:

select * from (
    select col1, col2
    from table a
    <....>
    order by col3
    limit by 200
) a
union all
select * from (
    select cola, colb
    from table b
    <....>
    order by colb
    limit by 300
) b

Это делает отдельные запросы более понятными и позволяет сортировать по разным параметрам в каждом запросе.Однако, используя способ выбранного ответа, он может стать более понятным в зависимости от сложности и от того, насколько связаны данные, потому что вы концептуализируете сортировку.Это также позволяет вам возвращать искусственный столбец в программу запросов, чтобы иметь контекст, который он может сортировать или упорядочивать.

Но этот способ имеет то преимущество, что он быстр, не вводит дополнительные переменные и позволяет легко разделять каждый запрос, включая сортировку.Возможность добавить ограничение - просто дополнительный бонус.

И, конечно, не стесняйтесь превратить объединение всех в объединение и добавить сортировку для всего запроса.Или добавьте искусственный идентификатор, и в этом случае этот способ упрощает сортировку по различным параметрам в каждом запросе, но в остальном он совпадает с принятым ответом.

8 голосов
/ 20 августа 2010

Запрос на объединение может иметь только одно главное предложение ORDER BY, IIRC.Чтобы получить это, в каждом запросе, составляющем больший запрос UNION, добавьте поле, которое будет тем полем, которое вы сортируете для UNION 's ORDER BY.

Например, у вас может быть что-то вроде

SELECT field1, field2, '1' AS union_sort
UNION SELECT field1, field2, '2' AS union_sort
UNION SELECT field1, field2, '3' AS union_sort
ORDER BY union_sort

. В этом поле union_sort может быть все, что вы хотите отсортировать.В этом примере просто помещаются результаты из первой таблицы во вторую, из второй таблицы во вторую и т. Д.

4 голосов
/ 10 июня 2011

Я получил эту работу на объединение плюс союз.

(SELECT 
   table1.column1,
   table1.column2,
   foo1.column4
 FROM table1, table2, foo1, table5
 WHERE table5.somerecord = table1.column1
 ORDER BY table1.column1 ASC, table1.column2 DESC
)

UNION

(SELECT
    ... Another complex query as above
)

ORDER BY column1 DESC, column2 ASC
0 голосов
/ 11 июля 2019

При использовании предложения ORDER BY внутри подзапроса, используемого вместе с UNION, mysql оптимизирует предложение ORDER BY.

Это потому, что по умолчанию UNION возвращает неупорядоченный список, поэтому ORDER BY ничего не будет делать.

Оптимизация упоминается в документах и гласит:

Чтобы применить ORDER BY или LIMIT к отдельному SELECT, поместите предложение внутри скобок, которые заключают в себе SELECT:

(SELECT a FROM t1 WHERE a=10 AND B=1 ORDER BY a LIMIT 10) UNION
(SELECT a FROM t2 WHERE a=11 AND B=2 ORDER BY a LIMIT 10);

Однако использование ORDER BY для отдельных операторов SELECT подразумевает ничего о порядке, в котором строки появляются в конечном результате потому что UNION по умолчанию создает неупорядоченный набор строк. Следовательно, использование ORDER BY в этом контексте обычно связано с LIMIT, так что он используется для определения подмножества выбранных строк извлечь для SELECT, даже если это не обязательно влияет порядок этих строк в конечном результате UNION. Если появляется ORDER BY без LIMIT в SELECT, он оптимизируется, потому что он будет иметь никакого эффекта в любом случае.

Последнее предложение немного вводит в заблуждение, потому что оно должно иметь эффект. Эта оптимизация вызывает проблему, когда вы находитесь в ситуации, когда вам нужно сделать заказ внутри подзапроса.

Чтобы заставить MySQL не выполнять эту оптимизацию, вы можете добавить предложение LIMIT следующим образом:

(SELECT 1 AS rank, id, add_date FROM my_table WHERE distance < 5 ORDER BY add_date LIMIT 9999999999)
UNION ALL
(SELECT 2 AS rank, id, add_date FROM my_table WHERE distance BETWEEN 5 AND 15 ORDER BY rank LIMIT 9999999999)
UNION ALL
(SELECT 3 AS rank, id, add_date from my_table WHERE distance BETWEEN 5 and 15 ORDER BY id LIMIT 9999999999)

Высокий LIMIT означает, что вы можете добавить OFFSET к полному запросу, если хотите сделать что-то, например, нумерацию страниц.

Это также дает вам дополнительное преимущество, заключающееся в возможности ORDER BY различных столбцов для каждого союза.

0 голосов
/ 20 августа 2010

Я пытался добавить порядок по каждому из запросов до объединения, как

(select * from table where distance=0 order by add_date) 
union 
(select * from table where distance>0 and distance<=5 order by add_date)

но это не сработало. На самом деле он не выполнял упорядочение в строках из каждого выбора.

Я думаю, вам нужно будет сохранить порядок снаружи и добавить столбцы в предложении where к заказу, что-то вроде

(select * from table where distance=0) 
union 
(select * from table where distance>0 and distance<=5) 
order by distance, add_date

Это может быть немного сложно, так как вы хотите сгруппировать по диапазонам, но я думаю, что это должно быть выполнимо.

0 голосов
/ 20 августа 2010

Это потому, что вы сортируете весь набор результатов, вы должны отсортировать каждую часть объединения по отдельности, или вы можете использовать ORDER BY (что-то, то есть расстояние подзапроса) THEN (что-то, то есть идентификатор строки)

0 голосов
/ 20 августа 2010

Попробуйте:

SELECT result.* 
FROM (
 [QUERY 1]
 UNION
 [QUERY 2]
) result
ORDER BY result.id

Где [QUERY 1] и [QUERY 2] - это два ваших запроса, которые вы хотите объединить.

...