복붙노트

[SQL] 여러 열에서 최소 값을 선택하는 가장 좋은 방법은 무엇입니까?

SQL

여러 열에서 최소 값을 선택하는 가장 좋은 방법은 무엇입니까?

SQL Server 2005에서 다음 테이블을 감안할 때 :

ID   Col1   Col2   Col3
--   ----   ----   ----
1       3     34     76  
2      32    976     24
3       7    235      3
4     245      1    792

쿼리를 작성하는 가장 좋은 방법이 무엇 그 수율은 다음과 같은 결과 (즉, 그 하나의 수율 최종 열 - 각 행 COL1, Col2의 밖으로 minium 값을 포함하는 열 및 골) δ

ID   Col1   Col2   Col3  TheMin
--   ----   ----   ----  ------
1       3     34     76       3
2      32    976     24      24
3       7    235      3       3
4     245      1    792       1

최신 정보:

실제 시나리오에서 설명 (나는 감동적인에서 말했듯이)에 대한 데이터베이스가 제대로 정상화됩니다. 이러한 "배열"열이 실제 테이블에 아니지만 보고서에 요구되는 결과 집합에 있습니다. 그리고 새로운 요구 사항이 보고서는이 MINVALUE 열을 필요로한다는 것이다. "감옥 카드의 나가"나는 기본 결과 집합을 변경할 수 없습니다, 따라서 나는 편리를위한 T-SQL을 찾고 있었다.

나는 CASE 방법은 아래에 언급과는 조금 복잡하지만 그것이 작동했습니다. 같은 행의 두 분의 값이 있다는 사실을 수용해야하기 때문에 답변에 명시된 것보다 그것은 또한 더 복잡하다.

어쨌든, 난 내 제약 주어진 꽤 잘 작동, 내 현재의 솔루션을 게시 할 거라고 생각했다. 그것은 UNPIVOT 연산자를 사용

with cte (ID, Col1, Col2, Col3)
as
(
    select ID, Col1, Col2, Col3
    from TestTable
)
select cte.ID, Col1, Col2, Col3, TheMin from cte
join
(
    select
        ID, min(Amount) as TheMin
    from 
        cte 
        UNPIVOT (Amount for AmountCol in (Col1, Col2, Col3)) as unpvt
    group by ID
) as minValues
on cte.ID = minValues.ID

나는 그것이 (난 그냥 새로운 MINVALUE 열 요구 사항에 대한 모든 쿼리를 재 설계 할 수없는)이 주어진 상황에서 내가 최상의 성능을 제공하기 위해이 기대하지 않는 것이 선행 말하지만,거야 꽤 우아한 "감옥에서 나가 카드".

해결법

  1. ==============================

    1.이 작업을 수행하는 방법에는 여러 가지가 될 가능성이 있습니다. 나의 제안은 케이스를 사용하는 것입니다 / 때 그것을 할 수 있습니다. 3 열, 그것은 나쁘지 않다.

    이 작업을 수행하는 방법에는 여러 가지가 될 가능성이 있습니다. 나의 제안은 케이스를 사용하는 것입니다 / 때 그것을 할 수 있습니다. 3 열, 그것은 나쁘지 않다.

    Select Id,
           Case When Col1 < Col2 And Col1 < Col3 Then Col1
                When Col2 < Col1 And Col2 < Col3 Then Col2 
                Else Col3
                End As TheMin
    From   YourTableNameHere
    
  2. ==============================

    2.사용 CROSS이 적용됩니다

    사용 CROSS이 적용됩니다

    SELECT ID, Col1, Col2, Col3, MinValue
    FROM YourTable
    CROSS APPLY (SELECT MIN(d) MinValue FROM (VALUES (Col1), (Col2), (Col3)) AS a(d)) A
    

    SQL 바이올린

  3. ==============================

    3.

    SELECT ID, Col1, Col2, Col3, 
        (SELECT MIN(Col) FROM (VALUES (Col1), (Col2), (Col3)) AS X(Col)) AS TheMin
    FROM Table
    
  4. ==============================

    4.MySQL의에서이를 사용 :

    MySQL의에서이를 사용 :

    select least(col1, col2, col3) FROM yourtable
    
  5. ==============================

    5.당신은 트위스트와 함께 "무력"방법을 사용할 수 있습니다 :

    당신은 트위스트와 함께 "무력"방법을 사용할 수 있습니다 :

    SELECT CASE
        WHEN Col1 <= Col2 AND Col1 <= Col3 THEN Col1
        WHEN                  Col2 <= Col3 THEN Col2
        ELSE                                    Col3
    END AS [Min Value] FROM [Your Table]
    

    첫 번째 경우 조건이 COL1이 가장 작은 값이 아닙니다 보장에 실패하면, 따라서 당신은 조건의 나머지를 제거 할 수 있습니다. 마찬가지로 이후의 조건. 오 열의 쿼리가된다 :

    SELECT CASE
        WHEN Col1 <= Col2 AND Col1 <= Col3 AND Col1 <= Col4 AND Col1 <= Col5 THEN Col1
        WHEN                  Col2 <= Col3 AND Col2 <= Col4 AND Col2 <= Col5 THEN Col2
        WHEN                                   Col3 <= Col4 AND Col3 <= Col5 THEN Col3
        WHEN                                                    Col4 <= Col5 THEN Col4
        ELSE                                                                      Col5
    END AS [Min Value] FROM [Your Table]
    

    참고 두 개 이상의 다음 열 <= 우리는 가능한 한 빨리으로 CASE 문을 종료 보장 사이에 넥타이가있는 경우.

  6. ==============================

    6.그것은 사람들이 그냥하면 원하는 결과를 달성하기 훨씬 쉬운 방법이있는 의미있는 정보를 추출하는 SQL "체조"를 요구하는 방법으로, 자신의 데이터를 저장 주장하는 것이 이상하다 - 그렇게 할 수있는 가장 좋은 방법은 그것을 할 수 없습니다 아마 조금 더 나은 스키마를 구성 :-)

    그것은 사람들이 그냥하면 원하는 결과를 달성하기 훨씬 쉬운 방법이있는 의미있는 정보를 추출하는 SQL "체조"를 요구하는 방법으로, 자신의 데이터를 저장 주장하는 것이 이상하다 - 그렇게 할 수있는 가장 좋은 방법은 그것을 할 수 없습니다 아마 조금 더 나은 스키마를 구성 :-)

    이 작업을 수행하는 올바른 방법은, 내 의견으로는, 다음 표를하는 것입니다 :

    ID    Col    Val
    --    ---    ---
     1      1      3
     1      2     34
     1      3     76
    
     2      1     32
     2      2    976
     2      3     24
    
     3      1      7
     3      2    235
     3      3      3
    
     4      1    245
     4      2      1
     4      3    792
    

    ID와 / 골은 기본 키로 (여분의 키와 가능성이 골, 필요에 따라). 그런 다음 쿼리 TBL에서 간단한 선택 분 (발을)이되고 당신은 여전히 ​​사용하여 별도로 개인의 오래된 열을 '취급 할 수있는 다른 쿼리에서 COL = 2. 이것은 또한 '옛 열'의 수는 증가 할 전망 쉽게 확장 할 수 있습니다.

    이 쿼리 훨씬 쉬워집니다. 만약 당신이 데이터베이스 행의 배열처럼 보이는, 당신은 아마 뭔가 잘못하고 있다는 것을 뭔가를하고 데이터를 구조 조정에 대해 생각해야한다면 내가 사용하는 경향이 일반적인 가이드 라인이다.

    어떤 이유로 당신이 그 열을 변경할 수없는 경우에는, 나는 삽입 및 업데이트 트리거를 사용하는 것이 좋습니다 이러한 트리거가 COL1 / 2 / 3에 최소로 설정 다른 열을 추가 할 것입니다. 이 거리에서 작업의 '비용'으로 이동하여 자신이 속한 갱신 / 삽입을 선택합니다 - 훨씬 더 자주 쓰기에 비용을 초래하는 것은 시간이 지남에 따라 더 효율적 경향이 있으므로 기록보다 읽어 내 경험에서 대부분의 데이터베이스 테이블.

    다른 열 중 하나가 변경 될 때 즉, 행의 최소 단의 당신은, (데이터가 변경되지 않은 경우 낭비)를 선택 할 때마다 그것을하지 계산해야 할 때 그래서, 변경합니다. 그런 다음 테이블 등으로 끝낼 것입니다 :

    ID   Col1   Col2   Col3   MinVal
    --   ----   ----   ----   ------
     1      3     34     76        3
     2     32    976     24       24
     3      7    235      3        3
     4    245      1    792        1
    

    다른 컬럼의 추가는 DB에 더 많은 공간을 차지하고 삽입을 위해 약간 느립니다 - 데이터 만 삽입 / 업데이트에 변경하기 때문에 선택시 의사 결정을하는 다른 옵션은 성능 현명한 일반적으로 나쁜 생각 업데이트는하지만, 훨씬 빠른 선택이 될 수 있습니다 - 명시된 선호하는 방법은,이 우선 순위에 의존해야하지만, 대부분의 테이블은 훨씬 더 자주 쓸 것보다 읽습니다.

  7. ==============================

    7.열이 정수는 당신의 예에서와 같이 인 경우에 나는 함수를 만들 것입니다 :

    열이 정수는 당신의 예에서와 같이 인 경우에 나는 함수를 만들 것입니다 :

    create function f_min_int(@a as int, @b as int) 
    returns int
    as
    begin
        return case when @a < @b then @a else coalesce(@b,@a) end
    end
    

    나는 그것을 사용할 필요가 다음 때 나는 할 것이다 :

    select col1, col2, col3, dbo.f_min_int(dbo.f_min_int(col1,col2),col3)
    

    위에서되고보다 당신은 5 열이있는 경우

    select col1, col2, col3, col4, col5,
    dbo.f_min_int(dbo.f_min_int(dbo.f_min_int(dbo.f_min_int(col1,col2),col3),col4),col5)
    
  8. ==============================

    8.또한 통합 쿼리와 함께이 작업을 수행 할 수 있습니다. 열 수가 증가, 당신은 쿼리를 수정해야하지만, 적어도 그것은 바로 앞으로 수정 될 것입니다.

    또한 통합 쿼리와 함께이 작업을 수행 할 수 있습니다. 열 수가 증가, 당신은 쿼리를 수정해야하지만, 적어도 그것은 바로 앞으로 수정 될 것입니다.

    Select T.Id, T.Col1, T.Col2, T.Col3, A.TheMin
    From   YourTable T
           Inner Join (
             Select A.Id, Min(A.Col1) As TheMin
             From   (
                    Select Id, Col1
                    From   YourTable
    
                    Union All
    
                    Select Id, Col2
                    From   YourTable
    
                    Union All
    
                    Select Id, Col3
                    From   YourTable
                    ) As A
             Group By A.Id
           ) As A
           On T.Id = A.Id
    
  9. ==============================

    9.이 브 루트 포스하지만 작품입니다

    이 브 루트 포스하지만 작품입니다

     select case when col1 <= col2 and col1 <= col3 then col1
               case when col2 <= col1 and col2 <= col3 then col2
               case when col3 <= col1 and col3 <= col2 then col3
        as 'TheMin'
               end
    
    from Table T
    

    ... 분 () 하나의 열이 아닌 열에서 작동하기 때문이다.

  10. ==============================

    10.이 질문에 두 그리고이 질문이 대답하려고합니다.

    이 질문에 두 그리고이 질문이 대답하려고합니다.

    정리 해보에서는 SQL Server와 당신이 붙어 있으며, 오라클은이를 위해 기능이 내장되어 있다는 것입니다 중 하나를 사용자 정의 함수를 정의하거나 경우 문을 사용.

  11. ==============================

    11.여러 열 최선은 두 개의 숫자 열에 대한 그러나, CASE 문을 사용하려면 i와 j 당신은 간단한 계산을 사용할 수 있습니다 :

    여러 열 최선은 두 개의 숫자 열에 대한 그러나, CASE 문을 사용하려면 i와 j 당신은 간단한 계산을 사용할 수 있습니다 :

    분 (I, J) = (I + J) / 2 - ABS (I-J) / 2

    이 수식은 여러 열의 최소 값을 얻기 위해 사용될 수 있지만 실제로는 것, (2) 과거 분 분 (i, j, k)를 질러 (I, 분 (j, K))

  12. ==============================

    12.저장 프로 시저를 만들 수 있다면, 그것은 값의 배열을 걸릴 수 있습니다, 당신은 그냥 전화를 할 수있다.

    저장 프로 시저를 만들 수 있다면, 그것은 값의 배열을 걸릴 수 있습니다, 당신은 그냥 전화를 할 수있다.

  13. ==============================

    13.

    select *,
    case when column1 < columnl2 And column1 < column3 then column1
    when columnl2 < column1 And columnl2 < column3 then columnl2
    else column3
    end As minValue
    from   tbl_example
    
  14. ==============================

    14.노조 쿼리에 작은 트위스트 :

    노조 쿼리에 작은 트위스트 :

    DECLARE @Foo TABLE (ID INT, Col1 INT, Col2 INT, Col3 INT)
    
    INSERT @Foo (ID, Col1, Col2, Col3)
    VALUES
    (1, 3, 34, 76),
    (2, 32, 976, 24),
    (3, 7, 235, 3),
    (4, 245, 1, 792)
    
    SELECT
        ID,
        Col1,
        Col2,
        Col3,
        (
            SELECT MIN(T.Col)
            FROM
            (
                SELECT Foo.Col1 AS Col UNION ALL
                SELECT Foo.Col2 AS Col UNION ALL
                SELECT Foo.Col3 AS Col 
            ) AS T
        ) AS TheMin
    FROM
        @Foo AS Foo
    
  15. ==============================

    15.당신은 SQL 2005을 사용하는 경우는 다음과 같이 깔끔한 일을 할 수 있습니다 :

    당신은 SQL 2005을 사용하는 경우는 다음과 같이 깔끔한 일을 할 수 있습니다 :

    ;WITH    res
              AS ( SELECT   t.YourID ,
                            CAST(( SELECT   Col1 AS c01 ,
                                            Col2 AS c02 ,
                                            Col3 AS c03 ,
                                            Col4 AS c04 ,
                                            Col5 AS c05
                                   FROM     YourTable AS cols
                                   WHERE    YourID = t.YourID
                                 FOR
                                   XML AUTO ,
                                       ELEMENTS
                                 ) AS XML) AS colslist
                   FROM     YourTable AS t
                 )
        SELECT  YourID ,
                colslist.query('for $c in //cols return min(data($c/*))').value('.',
                                                'real') AS YourMin ,
                colslist.query('for $c in //cols return avg(data($c/*))').value('.',
                                                'real') AS YourAvg ,
                colslist.query('for $c in //cols return max(data($c/*))').value('.',
                                                'real') AS YourMax
        FROM    res
    

    당신은 너무 많은 사업자에서 길을 잃지 않는이 방법 :)

    그러나, 이것은 다른 선택보다 느릴 수 있습니다.

    그것은 당신의 선택입니다 ...

  16. ==============================

    16.나는 임시 테이블을 사용하여 아래 여러 날짜의 최소를 얻을 수 있습니다. 첫 번째 임시 테이블은 두 번째 임시 테이블은 다양한 열 및 날짜 열이 있기 때문에 많은 패스로 사용하여 최소 날짜를 가져옵니다 다양한 날짜를 얻을 테이블 (뿐만 아니라 쿼리에 대한 다른 값을) 여러 합류 쿼리합니다.

    나는 임시 테이블을 사용하여 아래 여러 날짜의 최소를 얻을 수 있습니다. 첫 번째 임시 테이블은 두 번째 임시 테이블은 다양한 열 및 날짜 열이 있기 때문에 많은 패스로 사용하여 최소 날짜를 가져옵니다 다양한 날짜를 얻을 테이블 (뿐만 아니라 쿼리에 대한 다른 값을) 여러 합류 쿼리합니다.

    이것은 기본적으로 통합 쿼리와 같이 패스의 같은 번호가 필요하지만,보다 효율적으로 할 수있다 (경험을 바탕으로하지만, 테스트를해야합니다). 효율성이 경우 (8,000 기록)의 문제가 아니었다. 하나는 인덱스 등을 할 수

    --==================== this gets minimums and global min
    if object_id('tempdb..#temp1') is not null
        drop table #temp1
    if object_id('tempdb..#temp2') is not null
        drop table #temp2
    
    select r.recordid ,  r.ReferenceNumber, i.InventionTitle, RecordDate, i.ReceivedDate
    , min(fi.uploaddate) [Min File Upload], min(fi.CorrespondenceDate) [Min File Correspondence]
    into #temp1
    from record r 
    join Invention i on i.inventionid = r.recordid
    left join LnkRecordFile lrf on lrf.recordid = r.recordid
    left join fileinformation fi on fi.fileid = lrf.fileid
    where r.recorddate > '2015-05-26'
     group by  r.recordid, recorddate, i.ReceivedDate,
     r.ReferenceNumber, i.InventionTitle
    
    
    
    select recordid, recorddate [min date]
    into #temp2
    from #temp1
    
    update #temp2
    set [min date] = ReceivedDate 
    from #temp1 t1 join #temp2 t2 on t1.recordid = t2.recordid
    where t1.ReceivedDate < [min date] and  t1.ReceivedDate > '2001-01-01'
    
    update #temp2 
    set [min date] = t1.[Min File Upload]
    from #temp1 t1 join #temp2 t2 on t1.recordid = t2.recordid
    where t1.[Min File Upload] < [min date] and  t1.[Min File Upload] > '2001-01-01'
    
    update #temp2
    set [min date] = t1.[Min File Correspondence]
    from #temp1 t1 join #temp2 t2 on t1.recordid = t2.recordid
    where t1.[Min File Correspondence] < [min date] and t1.[Min File Correspondence] > '2001-01-01'
    
    
    select t1.*, t2.[min date] [LOWEST DATE]
    from #temp1 t1 join #temp2 t2 on t1.recordid = t2.recordid
    order by t1.recordid
    
  17. ==============================

    17.

    SELECT [ID],
                (
                    SELECT MIN([value].[MinValue])
                    FROM
                    (
                        VALUES
                            ([Col1]),
                            ([Col1]),
                            ([Col2]),
                            ([Col3])
                    ) AS [value] ([MinValue])
               ) AS [MinValue]
    FROM Table;
    
  18. ==============================

    18.당신은 당신이 보통 상태 코드, 찾고있는 값을 알고 있다면, 다음이 도움이 될 수 있습니다 :

    당신은 당신이 보통 상태 코드, 찾고있는 값을 알고 있다면, 다음이 도움이 될 수 있습니다 :

    select case when 0 in (PAGE1STATUS ,PAGE2STATUS ,PAGE3STATUS,
    PAGE4STATUS,PAGE5STATUS ,PAGE6STATUS) then 0 else 1 end
    FROM CUSTOMERS_FORMS
    
  19. ==============================

    19.나는 그 질문은 오래 알고 있지만 나는 대답의 필요성에 아직도 내가 @ paxdiablo's 대답에 트위스트 인 내 자신을 고안했다, 그래서 다른 답변에 만족하지 않았다.

    나는 그 질문은 오래 알고 있지만 나는 대답의 필요성에 아직도 내가 @ paxdiablo's 대답에 트위스트 인 내 자신을 고안했다, 그래서 다른 답변에 만족하지 않았다.

    나는 SAP ASE 16.0의 땅에서오고, 난 단지 이럴 유효 하나의 행의 다른 컬럼에 저장되어있는 특정 데이터의 통계를 들여다 필요 (그들은 다른 시간을 나타내는 - 뭔가 도착을 계획 할 때,이 때 예상 있었는지 작업이 시작하고 마지막으로) 실제 시간 것이었다. 따라서 나는 임시 테이블의 행으로 전치 열을했다 일반적으로이 이상 내 쿼리를 미리 형성.

    N.B. 아니 획일적 인 솔루션 앞서!

    CREATE TABLE #tempTable (ID int, columnName varchar(20), dataValue int)
    
    INSERT INTO #tempTable 
      SELECT ID, 'Col1', Col1
        FROM sourceTable
       WHERE Col1 IS NOT NULL
    INSERT INTO #tempTable 
      SELECT ID, 'Col2', Col2
        FROM sourceTable
       WHERE Col2 IS NOT NULL
    INSERT INTO #tempTable 
      SELECT ID, 'Col3', Col3
        FROM sourceTable
       WHERE Col3 IS NOT NULL
    
    SELECT ID
         , min(dataValue) AS 'Min'
         , max(dataValue) AS 'Max'
         , max(dataValue) - min(dataValue) AS 'Diff' 
      FROM #tempTable 
      GROUP BY ID
    

    이 630,000 행의 소스 세트에 약 30 초 걸렸 만 인덱스 데이터, 시간이 중요한 과정에 있지만, 한 번 데이터 검사 또는 엔드 - 중 - 일 보고서 당신이 될 수 같은 것들에 대한 실행 그렇게하지 않는 것을 사용 좋은 (그러나 동료 나 상사, 제발로이를 확인!). 나를 위해이 스타일의 홈페이지 보너스 내가 쉽게 데이터를 통해 copyied하고 특히 한번 더 / 덜 열 변화 등, 그룹화 필터링을 사용할 수있는 것이 었습니다.

    추가 데이터 (COLUMNNAME, maxes는 ...) 당신이 그들을 필요로하지 않을 수 있습니다, 그래서 내 검색에서 저를 돕기 위해이었다; 어쩌면 몇 가지 아이디어를 촉발하기 위해 여기를 떠나 :-).

  20. from https://stackoverflow.com/questions/368351/whats-the-best-way-to-select-the-minimum-value-from-several-columns by cc-by-sa and MIT license