Недавно я наткнулся на этот интересный вопрос переполнения стека , когда пользователь по сути хотел убедиться, что полученные записи доставляются в четко определенном порядке.
Они написали
|
1
2
3
4
5
6
|
SELECT nameFROM productWHERE name IN ('CE367FAACDHCANPH-151556', 'CE367FAACEX9ANPH-153877', 'NI564FAACJSFANPH-162605', 'GE526OTACCD3ANPH-149839') |
У них есть
|
1
2
3
4
|
CE367FAACDHCANPH-151556CE367FAACEX9ANPH-153877GE526OTACCD3ANPH-149839NI564FAACJSFANPH-162605 |
Они хотели
|
1
2
3
4
|
CE367FAACDHCANPH-151556CE367FAACEX9ANPH-153877NI564FAACJSFANPH-162605GE526OTACCD3ANPH-149839 |
Очень часто, согласно вашим бизнес-правилам, порядок сортировки не является «естественным», как при числовой или буквенно-цифровой сортировке. Возможно, в GE526OTACCD3ANPH-149839 бизнес-правиле указано, что GE526OTACCD3ANPH-149839 должен отображаться последним в списке. Или пользователь может переставить названия продуктов на экране с помощью перетаскивания, создав новый порядок сортировки.
Конечно, мы могли бы обсудить, должна ли такая сортировка выполняться на уровне пользовательского интерфейса или нет, но давайте предположим, что бизнес-обоснование или требования к производительности или общая архитектура, необходимые для этой сортировки, должны выполняться в базе данных. Как это сделать? Через…
Сортировка по косвенности
На самом деле, вы хотите сортировать не по названию продукта, а по заранее заданному перечислению таких имен. Другими словами, вам нужна такая функция:
|
1
2
3
4
|
CE367FAACDHCANPH-151556 -> 1CE367FAACEX9ANPH-153877 -> 2NI564FAACJSFANPH-162605 -> 3GE526OTACCD3ANPH-149839 -> 4 |
С простым SQL, есть много способов сделать выше. Вот два из них ( также видно из моего ответа переполнения стека ):
Используя выражение CASE
Вы можете легко указать базе данных явное косвенное указание сортировки, используя выражение CASE в предложении ORDER BY :
|
01
02
03
04
05
06
07
08
09
10
11
12
|
SELECT nameFROM productWHERE name IN ('CE367FAACDHCANPH-151556', 'CE367FAACEX9ANPH-153877', 'NI564FAACJSFANPH-162605', 'GE526OTACCD3ANPH-149839')ORDER BY CASE WHEN name = 'CE367FAACDHCANPH-151556' THEN 1 WHEN name = 'CE367FAACEX9ANPH-153877' THEN 2 WHEN name = 'NI564FAACJSFANPH-162605' THEN 3 WHEN name = 'GE526OTACCD3ANPH-149839' THEN 4 END |
Обратите внимание, что я использовал синтаксис CASE WHEN predicate THEN value END , потому что он реализован на всех диалектах SQL. В качестве альтернативы ( если вы не используете Apache Derb y), вы также можете сохранить некоторые символы при наборе текста, написав:
|
1
2
3
4
5
6
|
ORDER BY CASE name WHEN 'CE367FAACDHCANPH-151556' THEN 1 WHEN 'CE367FAACEX9ANPH-153877' THEN 2 WHEN 'NI564FAACJSFANPH-162605' THEN 3 WHEN 'GE526OTACCD3ANPH-149839' THEN 4 END |
Конечно, это требует повторения одинаковых значений в предикате и в косвенной сортировке. Вот почему в некоторых случаях вам может повезти больше …
С помощью INNER JOIN
В следующем примере предикат и косвенность сортировки обрабатываются в простой производной таблице, которая INNER JOIN ‘связана с исходным запросом:
|
01
02
03
04
05
06
07
08
09
10
|
SELECT product.nameFROM productJOIN ( VALUES('CE367FAACDHCANPH-151556', 1), ('CE367FAACEX9ANPH-153877', 2), ('NI564FAACJSFANPH-162605', 3), ('GE526OTACCD3ANPH-149839', 4)) AS sort (name, sort)ON product.name = sort.nameORDER BY sort.sort |
В приведенном выше примере используется синтаксис PostgreSQL, но вы можете реализовать его в своей базе данных другим способом.
Использование API косвенной сортировки jOOQ
Направленность сортировки немного утомительна, поэтому jOOQ имеет специальный синтаксис для этого варианта использования, который также задокументирован в руководстве . Любой из следующих операторов выполняет то же самое, что и приведенный выше запрос:
|
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
|
// jOOQ generates 1, 2, 3, 4 as values in the// generated CASE expressionDSL.using(configuration) .select(PRODUCT.NAME) .from(PRODUCT) .where(NAME.in( "CE367FAACDHCANPH-151556", "CE367FAACEX9ANPH-153877", "NI564FAACJSFANPH-162605", "GE526OTACCD3ANPH-149839" )) .orderBy(PRODUCT.NAME.sortAsc( "CE367FAACDHCANPH-151556", "CE367FAACEX9ANPH-153877", "NI564FAACJSFANPH-162605", "GE526OTACCD3ANPH-149839" )) .fetch();// You can choose your own indirection values to// be generated in the CASE expression .orderBy(PRODUCT.NAME.sort( new HashMap<String, Integer>() {{ put("CE367FAACDHCANPH-151556", 2); put("CE367FAACEX9ANPH-153877", 3); put("NI564FAACJSFANPH-162605", 5); put("GE526OTACCD3ANPH-149839", 8); }} )) |
Вывод
Переадресация сортировки — это хороший трюк, чтобы время от времени задирать рукава. Никогда не забывайте, что вы можете поместить почти произвольные выражения столбцов в предложение ORDER BY оператора SQL. Используй их!
| Ссылка: | Как реализовать косвенную сортировку в SQL от нашего партнера по JCG Лукаса Эдера из блога JAVA, SQL и JOOQ . |