Получение минимум двух значений в SQL

У меня есть две переменные, одна называется PaidThisMonth, а другая - OwedPast. Они оба являются результатом некоторых подзапросов в SQL. Как я могу выбрать меньшее из двух и вернуть его как значение под названием PaidForPast?

Функция MIN работает с столбцами, а не с переменными.

Ответ 1

Вариант использования:

   Select Case When @PaidThisMonth < @OwedPast 
               Then @PaidThisMonth Else @OwedPast End PaidForPast

В качестве встроенной таблицы используется UDF

CREATE FUNCTION Minimum
(@Param1 Integer, @Param2 Integer)
Returns Table As
Return(Select Case When @Param1 < @Param2 
                   Then @Param1 Else @Param2 End MinValue)

Использование:

Select MinValue as PaidforPast 
From dbo.Minimum(@PaidThisMonth, @OwedPast)

ДОПОЛНЕНИЕ:   Вероятно, это лучше всего подходит для адресации только двух возможных значений, если их больше двух, рассмотрите ответ крейга, используя предложение "Значения".

Ответ 2

SQL Server 2012 и 2014 поддерживает функцию IIF (продолжение, истина, ложь). Таким образом, для минимального выбора вы можете использовать его как

SELECT IIF(first>second, second, first) the_minimal FROM table

Хотя IIF - это просто сокращение для написания CASE...WHEN...ELSE, его легче писать.

Ответ 3

Решения, использующие CASE, IIF и UDF, являются адекватными, но непрактичными при распространении проблемы на общий случай с использованием более чем двух сравнительных значений. Обобщенные решение в SQL Server 2008+ использует странное приложение предложения VALUES:

SELECT
PaidForPast=(SELECT MIN(x) FROM (VALUES (PaidThisMonth),(OwedPast)) AS value(x))

Кредит на этом сайте: http://sqlblog.com/blogs/jamie_thomson/archive/2012/01/20/use-values-clause-to-get-the-maximum-value-from-some-columns-sql-server-t-sql.aspx

Ответ 4

У меня была ситуация, когда мне приходилось находить максимум 4 комплексных выбора внутри обновления. При таком подходе вы можете иметь столько, сколько хотите!

Вы также можете заменить номера дополнительными выделениями

select max(x)
 from (
 select 1 as 'x' union
 select 4 as 'x' union
 select 3 as 'x' union
 select 2 as 'x' 
 ) a

Более сложное использование

 @answer = select Max(x)
           from (
                select @NumberA as 'x' union
                select @NumberB as 'x' union
                select @NumberC as 'x' union
                select (
                       Select Max(score) from TopScores
                       ) as 'x' 
     ) a

Я уверен, что UDF имеет лучшую производительность.

Ответ 5

Для MySQL или PostgreSQL лучше использовать функции LEAST и GREATEST.

SELECT GREATEST(A.date0, B.date0) AS date0, 
       LEAST(A.date1, B.date1, B.date2) AS date1
FROM A, B
WHERE B.x = A.x

Оба описаны здесь: http://dev.mysql.com/doc/refman/5.0/en/comparison-operators.html

Ответ 6

Вот трюк, если вы хотите вычислить максимум (поле, 0):

SELECT (ABS(field) + field)/2 FROM Table

возвращает 0, если field отрицательный, else, return field.

Ответ 7

Используйте оператор CASE.

Пример B на этой странице должен быть близок к тому, что вы пытаетесь сделать:
http://msdn.microsoft.com/en-us/library/ms181765.aspx

Вот код со страницы:

USE AdventureWorks;
GO
SELECT   ProductNumber, Name, 'Price Range' = 
      CASE 
         WHEN ListPrice =  0 THEN 'Mfg item - not for resale'
         WHEN ListPrice < 50 THEN 'Under $50'
         WHEN ListPrice >= 50 and ListPrice < 250 THEN 'Under $250'
         WHEN ListPrice >= 250 and ListPrice < 1000 THEN 'Under $1000'
         ELSE 'Over $1000'
      END
FROM Production.Product
ORDER BY ProductNumber ;
GO

Ответ 8

Используйте временную таблицу для вставки диапазона значений, затем выберите min/max таблицы temp из хранимой процедуры или UDF. Это базовая конструкция, поэтому не стесняйтесь пересматривать по мере необходимости.

Например:

CREATE PROCEDURE GetMinSpeed() AS
BEGIN

    CREATE TABLE #speed (Driver NVARCHAR(10), SPEED INT);
    '
    ' Insert any number of data you need to sort and pull from
    '
    INSERT INTO #speed (N'Petty', 165)
    INSERT INTO #speed (N'Earnhardt', 172)
    INSERT INTO #speed (N'Patrick', 174)

    SELECT MIN(SPEED) FROM #speed

    DROP TABLE #speed

END

Ответ 9

Это работает до 5 дат и обрабатывает нули. Просто не мог заставить его работать как функция Inline.

CREATE FUNCTION dbo.MinDate(@Date1 datetime = Null,
                            @Date2 datetime = Null,
                            @Date3 datetime = Null,
                            @Date4 datetime = Null,
                            @Date5 datetime = Null)
RETURNS Datetime AS
BEGIN
--USAGE select dbo.MinDate('20120405',null,null,'20110305',null)
DECLARE @Output datetime;

WITH Datelist_CTE(DT)
AS (
        SELECT @Date1 AS DT WHERE @Date1 is not NULL UNION
        SELECT @Date2 AS DT WHERE @Date2 is not NULL UNION
        SELECT @Date3 AS DT WHERE @Date3 is not NULL UNION
        SELECT @Date4 AS DT WHERE @Date4 is not NULL UNION
        SELECT @Date5 AS DT WHERE @Date5 is not NULL
   )
Select @Output=Min(DT) FROM Datelist_CTE

RETURN @Output
END

Ответ 10

Опираясь на блестящую логику/код из mathematix и scottyc, я отправляю:

DECLARE @a INT, @b INT, @c INT = 0

WHILE @c < 100
    BEGIN
        SET @c += 1
        SET @a = ROUND(RAND()*100,0)-50
        SET @b = ROUND(RAND()*100,0)-50
        SELECT @a AS a, @b AS b,
            @a - ( ABS(@[email protected]) + (@[email protected]) ) / 2 AS MINab,
            @a + ( ABS(@[email protected]) + (@[email protected]) ) / 2 AS MAXab,
            CASE WHEN (@a <= @b AND @a = @a - ( ABS(@[email protected]) + (@[email protected]) ) / 2)
            OR (@a >= @b AND @a = @a + ( ABS(@[email protected]) + (@[email protected]) ) / 2)
            THEN 'Success' ELSE 'Failure' END AS Status
    END

Хотя переход от функции scottyc MIN к функции MAX должен был быть очевиден для меня, это не так, поэтому я решил для этого и включил его здесь: SELECT @a + (ABS (@b- @a ) + (@b- @a))/2. Случайно сгенерированные числа, хотя и не доказательство, должны хотя бы убедить скептиков в том, что обе формулы верны.