source

두 열의 최소값으로 정렬

manycodes 2023. 8. 9. 20:54
반응형

두 열의 최소값으로 정렬

사용합니다SQL Server 2008 R2.

두 열의 최소값으로 테이블을 정렬해야 합니다.

표는 다음과 같습니다.

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

나는 내 데이터가 최소 두 날짜까지 정렬되기를 원합니다.

이 테이블을 그런 식으로 정렬하는 가장 간단한 방법은 무엇입니까?

NULL 열이 아닙니다.다음의 ORDER BY 에 CASE 표현식을 추가해야 합니다.

SELECT Id, Date1, Date2
FROM YourTable
ORDER BY CASE 
           WHEN Date1 < Date2 THEN Date1 
           ELSE Date2 
         END 

NULL 가능 열입니다.Zohar Peled가 코멘트에 썼듯이 열이 무효일 경우 사용할 수 있습니다.ISNULL(그러나 사용하기에 더 좋습니다.COALESCEISNULL것은이기 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 여기에

을 합니다.CASE의현에 있는 ORDER BY:

 ORDER BY case when date1 < date2 then date1 else date2 end

편집:

null 값을 고려해야 하는 경우 추가coalesce():

 ORDER BY case when date1 < date2 then date1 else coalesce(date2,date1) end

설명:

date1 < date2인 경우 date1로 주문합니다. (여기서는 두 날짜가 모두 null이 아닙니다.)예전과 똑같이 작동합니다.

않으면 타기용을 합니다.COALESCE()null이 경우) null인 경우) null(두null인 경우)로합니다. date2(date2" null인 경우), date1(date2" null인 경우)로 순서를 합니다.

가장 간단한 방법은 다음과 같은 키워드를 사용하는 것입니다.

SELECT ID, Date1, Date2
FROM YourTable
ORDER BY (SELECT MIN(v) FROM (VALUES (Date1), (Date2)) AS value(v))

이 코드는 null 가능한 열에서도 모든 경우에 사용할 수 있습니다.

편집:

솔루션을 통한 솔루션을(를)COALESCE키워드가 범용이 아닙니다.다음과 같은 중요한 제한 사항이 있습니다.

  • 열이 다음과 같은 경우에는 작동하지 않습니다.Date 앞의 )01/01/1753)
  • 중 가 열중하다같은경작않다습니우동지하인 경우에는 하지 않습니다.NULL그것은 해석합니다.NULL합니다.datetime가치. 하지만 그것이 실제로 사실일까요?그렇지도 않습니다.datetime,그건 아무것도 아니다.
  • IF표현식은 두 개 이상의 열을 사용하면 훨씬 더 복잡해집니다.

질문에 따르면:

이 테이블을 그런 식으로 정렬하는 가장 간단한 방법은 무엇입니까?

가장 짧고 간단한 솔루션은 위에서 설명한 솔루션입니다. 다음과 같은 이유가 있습니다.

  • 구현하는 데 많은 코딩이 필요하지 않습니다. 한 줄만 더 추가하면 됩니다.
  • 열이 null인지 여부에 대해 신경 필요가 없습니다.코드를 사용하면 작동합니다.
  • 쉼표 뒤에 열을 추가하기만 하면 쿼리의 열 수를 확장할 수 있습니다.
  • 기능은 다음과 같이 작동합니다.Date코드를 수정할 필요가 없습니다.

편집 2:

조하르 펠레드는 다음과 같은 질서 방식을 제안했습니다.

나는 이 규칙에 따라 행을 정렬할 것입니다. 첫째, 둘 다 null일 때, 둘째, date1이 null일 때, 셋째, date2가 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

이것이 도움이 되고 비평가들을 기다리길 바랍니다.

이것은 다음과 같은 분기를 필요로 하지 않는 대체 솔루션일 수 있습니다.CASE WHEN이는 다음 공식을 기반으로 합니다.max(a,b)=1/2(a+b+|a−b|)여기에 기술된 바와 같이우리는 a와 busing의 절대값을 얻습니다.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))))

사용하지 않으려는 경우Case statement에 시대에Order By그렇다면 이것은 또 다른 접근법입니다, 단지 이동하는 것입니다.Case statementSelect

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

null 가능한 열을 처리하는 방법을 선호합니다.

SELECT Id, Date1, Date2
FROM YourTable
ORDER BY 
   CASE 
     WHEN Date1 < Date2 OR Date1 IS NULL THEN Date1 
     ELSE Date2 
   END 

최대 코드

는 중용사를 합니다.CROSS APPLY잘 , 공연잘모데요는겠르은요데▁i▁but는ance,▁perform모잘겠르공.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

저는 이 작업을 수행하는 방법에서 이 작업이 필요한 이유로 초점을 옮기고 대신 스키마를 변경할 것을 제안합니다.경험의 법칙은 데이터에 접근하기 위해 스턴트를 해야 하는 경우 잘못된 설계 결정이 있다는 것입니다.

이이지 않기 된 모든 인 SQL에 비해 .ORDER BY.

  • 이 작업을 자주 수행해야 하는 경우 두 날짜 중 최소 날짜는 응용 프로그램에 대해 독립적인 물리적 의미가 있어야 합니다.
    • 이는 별도의 열(또는 둘 중 하나를 대체하는 열)을 정당화합니다. 트리거에 의해 또는 경우에 따라 열이 둘 중 하나가 아닐 수 있을 정도로 의미가 독립적인 경우 수동으로 유지됩니다.

내 생각에 당신이 두 분야 모두에서 정렬하고 싶을 때.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

다른 방법이 있습니다.필요한 논리에 따라 결과 열을 계산하고 외부 논리에 따라 선택 항목을 열에 따라 정렬할 수 있습니다.이 경우 코드는 다음과 같습니다.

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

이 솔루션의 이점은 필요한 필터링 쿼리(내부 선택)를 추가할 수 있지만 인덱스는 유용하다는 것입니다.

다음 규칙에 따라 행을 정렬합니다.

  1. 둘 다 무효일 때
  2. date1이 null인 경우
  3. 날짜 2가 null인 경우
  4. min(날짜1,날짜2)

를 위해 이 게시물에 따르면 중첩된 사례는 간단하고 효율적입니다(표가 매우 큰 경우는 제외).

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

사용할 수 있습니다.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 또는 none null)이 아닙니다.true당신이 설정했더라도ansi_nullsoff는 그서당이원종하보류위해, 은처야합다니해리당신래기를 처리해야 합니다.null 당신이 있듯이, 피시다아시피.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

시나리오가 다른 경우에도 몇 가지 다른 해결책이 있습니다. 분리된 필드 내에서 여러 열(또는 계산)을 비교한 결과를 평가한 후 절별 주문 내부의 조건을 사용하지 않고 계산된 필드를 기준으로 마지막으로 정렬할 수 있습니다.

SELECT ID, Date1, Date2
FROM YourTable
ORDER BY (SELECT TOP(1) v FROM (VALUES (Date1), (Date2)) AS value(v) ORDER BY v)

@dyatchenko 답변과 매우 유사하지만 NULL 문제는 없습니다.

언급URL : https://stackoverflow.com/questions/29600737/sort-by-minimum-value-of-two-columns

반응형