Подтвердить что ты не робот

Сортировка по минимальному значению двух столбцов

Я использую SQL Server 2008 R2.

Мне нужно отсортировать таблицу по минимальному значению двух столбцов.

Таблица выглядит так:

ID: integer; 
Date1: datetime; 
Date2: datetime.

Я хочу, чтобы мои данные сортировались с минимальными двумя датами.

Каков самый простой способ сортировки этой таблицы?

4b9b3361

Ответ 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