SQL'de en az iki değerin elde edilmesi


180

İki değişkenim var, biri denir PaidThisMonth, diğeri denir OwedPast. Her ikisi de SQL'deki bazı alt sorguların sonucudur. İkisinden küçük olanı nasıl seçebilir ve başlıklı bir değer olarak PaidForPastnasıl döndürebilirim ?

MINFonksiyon sütunlar değil, değişkenler üzerinde çalışır.


1
Postgres veya MySQL kullanıyorsanız, @ Gil_Margolin yanıtına atlayın.
Noumenon

Yanıtlar:


127

Kullanım Durumu:

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

Satır içi tablo olarak UDF değeri

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

Kullanımı:

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

ADDENDUM: Bu muhtemelen iki olası değeri ele alırken en iyisidir, ikiden fazla varsa Craig'in Değerler yan tümcesini kullanarak yanıtını düşünün .


daha iyi anlaşılabilir sözdizimi: dönüş (minValue = @@ param1 <@@ param2 sonra @@ param1 else @@ param2 sona erdiğinde büyük / küçük harf seçin). Tamam bu normal olmayabilir, bilmiyorum. Ancak çok daha anlaşılır ve normalleştirilmesi gerekiyor.
Softlion

1
@ Craig'in aşağıdaki cevabını tercih etmenin bir başka nedeni de boş işleme nedeniyle. Karşılaştırılan değerleri null ise, ve bir değerler karşılaştırılır (bu ISNULL kullanımını eklemek sürece) ZAMAN testi sırasına bağlı olarak, boş anahtar durum gösterilmiştir kudreti dönüş sıfır ya da bir değerdir. Craig'in yaklaşımı her zaman benim için daha doğru görünen null olmayan değerin seçimini tercih edecektir, en azından şu anki kullanım durumumda null edilebilir tarihlerin karşılaştırılmasında.
Nij

148

SQL Server 2012 ve 2014 IIF (devam, doğru, yanlış) işlevini destekler. Böylece minimal seçim için kullanabilirsiniz

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

IIFCASE...WHEN...ELSE yazmak için bir kısayol olmakla birlikte , yazmak daha kolaydır.


8
IIFsadece sözdizimsel bir şekerdir CASE...WHEN...ELSE.
Salman A

55
Muhtemelen evet. Ama yazmak daha kolay.
Mert Gülsoy

1
@ MertGülsoy Ve okunması daha kolay, doğruluktan hemen sonra herkesin öncelik listesinin başında olmalı.
Daniel

119

CASE, IIF ve UDF kullanan çözeltiler yeterlidir, ancak sorunu 2'den fazla karşılaştırma değeri kullanarak genel duruma genişletirken kullanışsızdır. SQL Server 2008+ içindeki genelleştirilmiş çözüm, VALUES deyiminin garip bir uygulamasını kullanır:

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

Bu web sitesi nedeniyle kredi: http://sqlblog.com/blogs/jamie_thomson/archive/2012/01/20/use-values-clause-to-get-the-maximum-value-from-some-columns-sql- sunucu-t-sql.aspx


12
Bu en iyi cevaptır
FindOutIslamNow

min sıfır olmayan istiyorsanız:MIN(x*(case x when 0 then null else 1 end))
mpag

MartinC dört yıl önce aynı cevabı verdi ve aslında ikiden fazla değerle gösterdi ...
Auspex

4
Auspex, MartinC'nin cevabı ilgisiz. Bu cevap sendika kullanmıyor.
Craig

30

Bir güncellemede en fazla 4 karmaşık seçim bulmak zorunda olduğum bir durum vardı. Bu yaklaşımla istediğiniz kadar sahip olabilirsiniz!

Ayrıca sayıları ek seçimlerle de değiştirebilirsiniz

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

Daha karmaşık kullanım

 @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

Eminim bir UDF daha iyi bir performansa sahiptir.


Temel SQL olduğu için en çok hoşuma gitti. Ayrıca, UDF'ler daha hızlı olmak zorunda değildir. Çoğu sütun deposu için, her bir öznitelik (özniteliklere de filtre uygulayacağınızı varsayarım) paralel olarak hesaplanabilir ve yalnızca niteleme kümesi birleşir. Yani sendikalar kendi başlarına yavaş değiller.
Bouncner

basit ve harika.
ashleedawg

22

MySQL veya PostgreSQL 9.3+ için, LEASTve GREATESTfonksiyonlarını kullanmak daha iyi bir yoldur .

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

İle:

  • GREATEST(value [, ...]): Verilen değerlerden en büyük (maksimum değerli) bağımsız değişkeni döndürür
  • LEAST(value [, ...])Sağlanan değerlerden en küçük (minimum değerli) bağımsız değişkeni döndürür

Dokümantasyon bağlantıları:


Bu aynı zamanda PostgreSQL'de de çalışır (ve tam da aradığım şey :) Bkz: postgresql.org/docs/9.5/static/functions-conditional.html
Albert Vaca Cintora

1
Bu en iyi cevap.
Roberto Rodriguez

2
@RobertoRodriguez, sorunun MySQL veya PostgreSQL sorusunun bir parçası olarak etiketlenmesi en iyisi olacaktır. Soru özellikle tsql ile ilgiliydi, bu yüzden bu cevap hiç yardımcı olmuyor.
Jmaurier

Bu MSSQL için cevap değil
Mujah Maskey

13

Maksimum değerini (alan, 0) hesaplamak istiyorsanız bir püf noktası:

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

fieldnegatifse 0 döndürür , aksi takdirde döndürür field.


3
Yani, minimum hesaplamak için (@a, @b) şunları kullanabilirsiniz:SELECT @a - ( ABS(@a-@b) + (@a-@b) ) / 2
scottyc

1
ve tip taşması hakkında unutma;)
pkuderov

Bu kayan nokta hassasiyeti açısından tasarruf sağlıyor mu? Sonucun asla sıfıra yakın fakat negatif olmayacağı kesin mi?
Zuraff

6

Bir CASE deyimi kullanın.

Bu sayfadaki Örnek B yapmaya çalıştığınız şeye yakın olmalıdır:
http://msdn.microsoft.com/en-us/library/ms181765.aspx

Sayfadaki kod:

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

2

Değer aralığını eklemek için geçici tablo kullanın, ardından saklı yordam veya UDF içinden geçici tablonun min / maks değerini seçin. Bu temel bir yapıdır, bu yüzden gerektiğinde revize etmekten çekinmeyin.

Örneğin:

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

2

Bu, 5 tarihe kadar çalışır ve null değerlerini işler. Sadece bir Satır içi işlevi olarak çalışamadı.

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

MIN zaten boş değerlerini kaldıracağından WHERE Cümlelerine ihtiyacınız olmadığını fark ettiniz.
Lawrence

2

Mathematix ve scottyc'den parlak mantık / kod üzerine inşa ediyorum:

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(@a-@b) + (@a-@b) ) / 2 AS MINab,
            @a + ( ABS(@b-@a) + (@b-@a) ) / 2 AS MAXab,
            CASE WHEN (@a <= @b AND @a = @a - ( ABS(@a-@b) + (@a-@b) ) / 2)
            OR (@a >= @b AND @a = @a + ( ABS(@b-@a) + (@b-@a) ) / 2)
            THEN 'Success' ELSE 'Failure' END AS Status
    END

Her ne kadar scottyc'in MIN işlevinden MAX işlevine atlamak benim için açık olmalıydı, öyle değildi, bu yüzden çözdüm ve buraya dahil ettim: SELECT @a + (ABS (@ b- @ a) + ( @ b- @ a)) / 2. Rastgele üretilen sayılar, kanıt olmasa da, en azından her iki formülün de doğru olduğu konusunda şüpheleri ikna etmelidir.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.