110 votes

Quelle est la meilleure façon de sélectionner la valeur minimale dans plusieurs colonnes ?

Étant donné le tableau suivant dans SQL Server 2005 :

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

Quelle est la meilleure façon d'écrire la requête qui donne le résultat suivant (c'est-à-dire une requête qui donne la colonne finale - une colonne contenant les valeurs minimales de Col1, Col2 et Col 3) ? pour chaque ligne ) ?

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

UPDATE :

Pour plus de clarté (comme je l'ai dit dans les commentaires), dans le scénario réel, la base de données est la suivante correctement normalisé . Ces colonnes "tableau" ne se trouvent pas dans un tableau réel mais dans un ensemble de résultats requis dans un rapport. Et la nouvelle exigence est que le rapport a également besoin de cette colonne MinValue. Je ne peux pas modifier l'ensemble de résultats sous-jacent et je me suis donc tourné vers T-SQL pour obtenir une carte de sortie de prison pratique.

J'ai essayé l'approche CASE mentionnée ci-dessous et elle fonctionne, bien qu'elle soit un peu lourde. Elle est également plus compliquée que ce qui est indiqué dans les réponses, car il faut tenir compte du fait qu'il y a deux valeurs minimales dans la même ligne.

Quoi qu'il en soit, j'ai pensé publier ma solution actuelle qui, compte tenu de mes contraintes, fonctionne assez bien. Elle utilise l'opérateur 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

Je dirai d'emblée que je ne m'attends pas à ce que cela offre les meilleures performances, mais compte tenu des circonstances (je ne peux pas revoir toutes les requêtes uniquement pour la nouvelle exigence de la colonne MinValue), il s'agit d'une "carte de sortie de prison" assez élégante.

73voto

Nizam Points 1273

Utilisation 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

Fidèle à SQL

72voto

G Mastros Points 12241

Il existe probablement de nombreuses façons d'y parvenir. Je suggère d'utiliser Case/When pour le faire. Avec 3 colonnes, ce n'est pas trop difficile.

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

57voto

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

27voto

user3493139 Points 1

Sur MySQL, utilisez ceci :

select least(col1, col2, col3) FROM yourtable

13voto

Salman A Points 60620

Vous pouvez utiliser l'approche de la "force brute", mais avec une nuance :

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

Lorsque la première condition "when" échoue, elle garantit que Col1 n'est pas la plus petite valeur, ce qui permet de l'éliminer des autres conditions. Il en va de même pour les conditions suivantes. Pour cinq colonnes, votre requête devient :

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]

Notez que s'il y a égalité entre deux ou plusieurs colonnes, alors <= s'assure que nous quittons le CASE le plus tôt possible.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X