[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 및 Col 3 중 최소값을 포함하는 열인 최종 열을 생성하는 )?

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 열 요구 사항에 대해서만 모든 쿼리를 재 설계 할 수는 없음) 매우 우아한 “탈옥 카드”.



답변

이를 수행하는 방법은 여러 가지가 있습니다. 내 제안은 케이스 / 언제 사용하는 것입니다. 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


답변

사용 CROSS APPLY:

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

SQL 바이올린


답변

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


답변

MySQL에서는 다음을 사용하십시오.

select least(col1, col2, col3) FROM yourtable


답변

비틀어 “무력한 힘”접근 방식을 사용할 수 있습니다.

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

첫 번째 when 조건이 실패하면 Col1이 가장 작은 값이 아니라는 것을 보장하므로 나머지 조건에서 제거 할 수 있습니다. 후속 조건에서도 마찬가지입니다. 5 개의 열에 대한 쿼리는 다음과 같습니다.

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합니다.


답변

예에서와 같이 열이 정수이면 함수를 만듭니다.

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)


답변

그렇게 할 수있는 가장 좋은 방법은 아마도 되지 는 사람들이 그냥하면 원하는 결과를 달성하기 훨씬 쉬운 방법이있는 의미있는 정보를 추출하는 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/Col기본 키로 (그리고 아마도 Col여분의 키로서, 사용자의 요구에 따라). 그러면 쿼리가 단순 select min(val) from tbl해지며 where 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

select시간에 결정을 내려야하는 다른 옵션 은 일반적으로 데이터가 삽입 / 업데이트 할 때만 변경되므로 성능 측면에서 좋지 않습니다. 다른 열을 추가하면 DB에서 더 많은 공간을 차지하고 삽입 및 업데이트하지만 선택에 대해 훨씬 더 빠를 수 있습니다 . 선호하는 접근 방식은 우선 순위에 따라 달라야하지만 언급했듯이 대부분의 테이블은 작성된 것보다 훨씬 더 자주 읽습니다 .