Сортировка по минимальному значению двух столбцов
Я использую SQL Server 2008 R2
.
Мне нужно отсортировать таблицу по минимальному значению двух столбцов.
Таблица выглядит так:
ID: integer;
Date1: datetime;
Date2: datetime.
Я хочу, чтобы мои данные сортировались с минимальными двумя датами.
Каков самый простой способ сортировки этой таблицы?
Ответы
Ответ 1
NOT NULL столбцы. Вам нужно добавить CASE в ORDER BY в следующем:
SELECT Id, Date1, Date2
FROM YourTable
ORDER BY CASE
WHEN Date1 < Date2 THEN Date1
ELSE Date2
END
столбцы NULLABLE. Поскольку Zohar Peled писал в комментариях, если столбцы являются нулевыми, вы можете использовать ISNULL
(но лучше использовать COALESCE
вместо ISNULL
, потому что It ANSI SQL standard
) в следующем:
SELECT Id, Date1, Date2
FROM YourTable
ORDER BY CASE
WHEN COALESCE(Date1, '1753-01-01') < COALESCE(Date2, '1753-01-01') THEN Date1
ELSE Date2
END
Здесь вы можете прочитать информацию о стандартном формате ANSI 1753-01-01
здесь.
Ответ 2
Используйте выражение CASE
в ORDER BY
:
ORDER BY case when date1 < date2 then date1 else date2 end
Редактировать:
Если необходимо учитывать нулевые значения, добавьте coalesce()
:
ORDER BY case when date1 < date2 then date1 else coalesce(date2,date1) end
Объяснение:
Если дата1 <дата2, то заказ по дате1. (Обе даты здесь не равны нулю.) Работает так же, как и раньше.
В противном случае используйте COALESCE()
для упорядочивания по дате2 (когда date2 не равно нулю), или по дате1 (когда date2 равно нулю), или по нулю (если обе даты равны нулю.)
Ответ 3
Самый простой способ - использовать VALUES
ключевое слово, например следующее:
SELECT ID, Date1, Date2
FROM YourTable
ORDER BY (SELECT MIN(v) FROM (VALUES (Date1), (Date2)) AS value(v))
Этот код будет работать для всех случаев, даже с столбцами с нулевым.
Изменить:
Решение с ключевым словом COALESCE
не является универсальным. Он имеет важные ограничения:
- Он не будет работать, если столбцы имеют тип
Date
(если вы используете даты до 01/01/1753
)
- Он не будет работать, если один из столбцов
NULL
. Он интерпретирует
NULL
значение как минимальное значение datetime
. Но действительно ли это
правда? Это даже не datetime
, это ничего.
- Выражение
IF
будет намного сложнее, если мы используем более двух столбцов.
В соответствии с вопросом:
Каков самый простой способ сортировки этой таблицы?
Самое короткое и самое простое решение - это тот, который описан выше, потому что:
- Для его реализации не требуется много кодирования - просто добавьте еще одну строку.
- Вам не нужно заботиться о том, являются ли столбцы обнуляемыми или нет. Вы просто используете код, и он работает.
- Вы можете расширить количество столбцов в запросе, просто добавив его после запятой.
- Он работает с столбцами
Date
, и вам не нужно изменять код.
Изменить 2:
Зоар Пелед предложил следующий порядок:
Я бы заказал строки по этим правилам: во-первых, когда оба значения null, second, when date1 равно null, третье, когда дата 2 равна null, четвертая, min (date1, date2)
Итак, для этого случая решение может быть достигнуто с использованием того же подхода, как и следующее:
SELECT ID, Date1, Date2
FROM YourTable
ORDER BY
CASE WHEN Date1 IS NULL AND Date2 IS NULL THEN 0
WHEN Date1 IS NULL THEN 1
WHEN Date2 IS NULL THEN 2
ELSE 3 END,
(SELECT MIN(v) FROM (VALUES ([Date1]), ([Date2])) AS value(v))
Результат для этого кода ниже:
![The output result for *Zohar's* way of order]()
COALESCE
решение не будет сортировать таблицу таким образом. Он помещает строки, где по крайней мере одна ячейка значения NULL
. Его вывод следующий:
![Weird ORDER BY of <code>COALESCE</code> solution]()
Надеюсь, это поможет и ждет критиков.
Ответ 4
Если вы не хотите использовать Case statement
в Order By
, это другой подход, просто перемещая Case statement
в Select
SELECT Id, Date1, Date2 FROM
(SELECT Id, Date1, Date2
,CASE WHEN Date1 < Date2 THEN Date1 ELSE Date2 END as MinDate
FROM YourTable) as T
ORDER BY MinDate
Ответ 5
Это может быть альтернативное решение, которое не требует разветвления типа CASE WHEN
. Это основано на формуле max(a,b)=1/2(a+b+|a−b|)
, как описано здесь. Мы получаем абсолютные значения a и b, используя DATEDIFF
со ссылочной датой ('1773-01-01'
).
ORDER BY (DATEDIFF(d,'17730101' ,isnull(Startdate,enddate)) + DATEDIFF(d,'17730101' ,isnull(EndDate,Startdate))
- ABS(DATEDIFF(d,isnull(Startdate,enddate),isnull(EndDate,Startdate))))
Данные тестирования
Create Table #DateData(ID int Identity, Name varchar(15),Startdate datetime,EndDate DateTime)
Insert Into #DateData(Name,Startdate,EndDate) values ('myName','2015-04-17 18:48:27','2015-04-18 18:48:27')
Insert Into #DateData(Name,Startdate,EndDate) values ('myName','2015-04-19 18:48:27','2015-04-18 18:48:27')
Insert Into #DateData(Name,Startdate,EndDate) values ('myName','2015-04-20 18:48:27','2015-04-18 18:48:27')
Insert Into #DateData(Name,Startdate,EndDate) values ('myName','2015-04-11 18:48:27','2015-04-22 18:48:27')
Insert Into #DateData(Name,Startdate,EndDate) values ('myName','2015-05-09 18:48:27','2015-04-18 18:48:27')
Insert Into #DateData(Name,Startdate,EndDate) values ('myName','2015-04-17 19:07:38','2015-04-17 18:55:38')
Insert Into #DateData(Name,Startdate,EndDate) values ('myName','2015-04-17 19:07:38','2015-05-12 18:56:29')
Завершить запрос
select *
from #DateData order by (DATEDIFF(d,'17730101' ,isnull(Startdate,enddate)) + DATEDIFF(d,'17730101' ,isnull(EndDate,Startdate))
- ABS(DATEDIFF(d,isnull(Startdate,enddate),isnull(EndDate,Startdate))))
Ответ 6
Я предпочитаю этот способ обрабатывать столбцы с нулевым значением:
SELECT Id, Date1, Date2
FROM YourTable
ORDER BY
CASE
WHEN Date1 < Date2 OR Date1 IS NULL THEN Date1
ELSE Date2
END
Ответ 7
Код для max
Я использую CROSS APPLY
, я не уверен в производительности, но CROSS APPLY
часто имеет лучшую производительность в моем опыте.
CREATE TABLE #Test (ID INT, Date1 DATETIME, Date2 DATETIME)
INSERT INTO #Test SELECT 1, NULL, '1/1/1';INSERT INTO #Test SELECT 2, NULL, NULL;INSERT INTO #Test SELECT 3, '2/2/2', '3/3/1';INSERT INTO #Test SELECT 4, '3/3/3', '11/1/1'
SELECT t.ID, Date1, Date2, MinDate
FROM #TEST t
CROSS APPLY (SELECT MIN(d) MinDate FROM (VALUES (Date1), (Date2)) AS a(d)) md
ORDER BY MinDate
DROP TABLE #Test
Ответ 8
Я думаю, что если вы хотите сортировать по обоим полям date1
и date2
, вы должны иметь их оба в части ORDER BY
, например:
SELECT *
FROM aTable
ORDER BY
CASE WHEN date1 < date2 THEN date1
ELSE date2 END,
CASE WHEN date1 < date2 THEN date2
ELSE date1 END
Результат может быть таким:
date1 | date2
-----------+------------
2015-04-25 | 2015-04-21
2015-04-26 | 2015-04-21
2015-04-25 | 2015-04-22
2015-04-22 | 2015-04-26
Чтобы получить результат префекта с помощью значений Null
, используйте:
SELECT *
FROM aTable
ORDER BY
CASE
WHEN date1 IS NULL THEN NULL
WHEN date1 < date2 THEN date1
ELSE date2 END
,CASE
WHEN date2 IS NULL THEN date1
WHEN date1 IS NULL THEN date2
WHEN date1 < date2 THEN date2
ELSE date1 END
Результаты будут такими:
date1 | date2
-----------+------------
NULL | NULL
NULL | 2015-04-22
2015-04-26 | NULL
2015-04-25 | 2015-04-21
2015-04-26 | 2015-04-21
2015-04-25 | 2015-04-22
Ответ 9
Я бы сфокусировал внимание на том, как это сделать, и зачем вам это нужно, и вместо этого предлагаю изменить схему. Эмпирическое правило: если вам нужно тянуть трюки, чтобы получить доступ к вашим данным, есть плохое дизайнерское решение.
Как вы видели, эта задача очень не типична для SQL, поэтому, хотя это возможно, все предлагаемые методы мучительно медленны по сравнению с обычным ORDER BY
.
- Если вам нужно делать это часто, то минимум двух дат должен иметь определенный физический смысл для вашего приложения.
- Что оправдывает отдельный столбец (или, может быть, столбец, заменяющий один из двух), поддерживаемый триггером или даже вручную, если значение достаточно независимо для того, чтобы столбец не был ни в одном случае.
Ответ 10
Я бы заказал строки по этим правилам:
- когда оба значения null
- когда date1 имеет значение null
- когда дата 2 равна нулю
- min (date1, date2)
Для этого вложенный случай будет простым и эффективным (если таблица не очень большая) в соответствии с этим сообщением.
SELECT ID, Date1, Date2
FROM YourTable
ORDER BY
CASE
WHEN Date1 IS NULL AND Date2 IS NULL THEN 0
WHEN Date1 IS NULL THEN 1
WHEN Date2 IS NULL THEN 2
ELSE 3 END,
CASE
WHEN Date1 < Date2 THEN Date1
ELSE Date2
END
Ответ 11
Есть еще один вариант. Вы можете вычислить столбец результатов по необходимой логике и покрыть выбор по внешнему с помощью упорядочения по столбцу. В этом случае код будет выглядеть следующим образом:
select ID, x.Date1, x.Date2
from
(
select
ID,
Date1,
Date2,
SortColumn = case when Date1 < Date2 then Date1 else Date2 end
from YourTable
) x
order by x.SortColumn
Преимущество этого решения заключается в том, что вы можете добавлять необходимые запросы фильтрации (во внутреннем выборе), и все же индексы будут полезны.
Ответ 12
Вы можете использовать min
функцию в order by
:
select *
from [table] d
order by ( select min(q.t) from (
select d.date1 t union select d.date2) q
)
Вы также можете использовать оператор case
в order by
, но, как вы знаете, результат сравнения (>
и <
), любое значение (null или none null) с нулевым значением не равно true
, даже если вы установили ansi_nulls
в off
. поэтому для гарантирования нужного вам типа вам нужно обрабатывать null
s, как вы знаете в case
, если результат when
равен true
, тогда дальнейшие выражения when
не оцениваются, поэтому вы можете сказать
select * from [table]
order by case
when date1 is null then date2
when date2 is null then date1
when date1<date2 then date1 -- surely date1 and date2 are not null here
else date2
end
Также есть несколько других решений, если ваш сценарий отличается от другого, может быть, вы можете оценить результат сравнения нескольких столбцов (или вычисления) внутри разделенного поля и, наконец, упорядочить это вычисляемое поле без использования какого-либо условия в вашем предложении order by.
Ответ 13
SELECT ID, Date1, Date2
FROM YourTable
ORDER BY (SELECT TOP(1) v FROM (VALUES (Date1), (Date2)) AS value(v) ORDER BY v)
Очень похоже на ответ @dyatchenko, но без NULL issue