SQL Server, en yaygın çözüm hangisi değilse, BÜYÜK ve EN AZ destekliyor mu?


20

Bu soruyu gözden geçirdiğimizde , ihtiyaç duyulmaması gereken çok fazla iş var gibi görünüyor. Tarihi olan bir aralığı genişletmeye çalışıyorlar. Diğer veritabanları ise, sadece kullanmak istiyorsunuz greatestve least..

least(extendDate,min), greatest(extendDate,max)

Bunları kullanmaya çalıştığımda,

'least' is not a recognized built-in function name.
'greatest' is not a recognized built-in function name.

Bu, her iki yönde uzantıyı da kapsayacaktır.

Sorunun amaçları doğrultusunda, yine de münhasır menzil değişimi yapmanız gerekecektir.

Sadece SQL Server kullanıcılarının taklit leastve greatestişlevsellik için sorgu desenleri nasıl uyguladıklarını merak ediyorum .

Koşulları CASEifadelere dönüştürüyor musunuz veya Microsoft'un bu işlevi etkinleştiren bir uzantısı, üçüncü taraf eklentisi veya lisansı var mı?


Yanıtlar:


33

Yaygın bir yöntem VALUESyan CROSS APPLYtümceyi kullanmaktır ve iki sütun tek bir sütun olarak diğer ad olarak adlandırılır, ardından her birinin MINve işaretlerini elde etmektir MAX.

SELECT MIN(x.CombinedDate) AS least, MAX(x.CombinedDate) AS greatest
FROM   dbo.Users AS u
CROSS APPLY ( VALUES ( u.CreationDate ), ( u.LastAccessDate )) AS x ( CombinedDate );

Yazmanın başka yolları da var, örneğin UNION ALL

SELECT MIN(x.CombinedDate) AS least, MAX(x.CombinedDate) AS greatest
FROM   dbo.Users AS u
CROSS APPLY ( SELECT u.CreationDate UNION ALL SELECT u.LastAccessDate ) AS x(CombinedDate);

Ancak, sonuçta ortaya çıkan sorgu planları aynı görünmektedir.


14

Ayrıca değerleri bir alt sorguya satır içi olarak da koyabilirsiniz. Bunun gibi:

select (select max(i) from (values (1), (2), (5), (1), (6)) AS T(i)) greatest,
       (select min(i) from (values (1), (2), (5), (1), (6)) AS T(i)) least

3

Bu iyi bir başlangıç ​​olurdu -

CASE WHEN A > B THEN A ELSE B END

Bu iyi bir öneri ama soruda "durumun CASE ifadelerine açılması" ile ilgili
Evan Carroll

3

LEAST eşdeğeri:

IIF(@a < @b, @a, @b)

BÜYÜK eşdeğer:

IIF(@a > @b, @a, @b)

3
Bunu üç veya daha fazla değer için nasıl yaparsınız, örneğin least(5,6,7,8,9)?
a_horse_with_no_name

@a_horse_with_no_name İç içe geçmiş IIF'leri kullanma
Elnur

Bu yaklaşım hızlı bir şekilde okunması ve doğrulanması zorlaşacaktır ... Performans açısından nasıl ilerliyor?
Dodecaphone

0

Kullanıcı tanımlı işlevler oluşturuyorum, örn.

create function dbo.udf_LeastInt(@a int, @b int)
returns int
with schemabinding
as
begin
  return case when @a <= @b then @a 
              when @b < @a  then @b
              else null
         end
end

Basit durumlarda çalışabilse de, bu yaklaşımla ilgili birkaç sorun vardır:

  • Rahatsız edici bir şekilde, her veri türü için ayrı işlevler yapmanız gerekir.
  • Yalnızca 2 parametreyi yönetir, bu nedenle birçok parametreyi işlemek veya aynı işlevlerin iç içe çağrılarını kullanmak için daha fazla işleve ihtiyaç duyulabilir.
  • Bir skaler fonksiyondan ziyade bir inline TVF olarak daha iyi (daha verimli) olacaktır. Bu, kalpte skaler fonksiyonların uygulanmasıyla ilgilidir. Bu konuda birçok blog var, örneğin SQL 101: Paralellik İnhibitörleri - Skaler Kullanıcı Tanımlı Fonksiyonlar (John Kehayias tarafından .
  • Bağımsız değişkenlerden biri null ise, null değerini döndürür. Bu, leastoperatörün Oracle ve MySQL'de yaptıklarıyla eşleşir , ancak Postgres'ten farklıdır. Ancak null'a karşı bu zırh, daha ayrıntılı hale getirir (null olmayacaklarını biliyorsanız, bir ova case when @a <= @b then @a else @b endişe yarayacaktır).

Sonuç olarak, caseeğer performans önemliyse , ifadeyi uzun süre yazmak daha iyi olabilir . Hatta casekarşılaştırmak için birkaç değer olduğunda istemci tarafında iç içe ifadeler oluşturmaya başvurdum .


0

@ Ed-avis cevabına yorum eklemek niyetindeydim, ancak itibar eksikliği nedeniyle bunu yapamadım, bu yüzden cevabının uzantısı olarak yayınladım.

Ben de dezavantajı "can sıkıcı bir şekilde her veri türü için ayrı işlevler yapmak zorunda." SQL_VARIANT kullanma .

İşte benim uygulama:

CREATE OR ALTER FUNCTION my_least(@a SQL_VARIANT, @b SQL_VARIANT)
returns SQL_VARIANT
with schemabinding
as
begin
  return case when @a <= @b then @a 
              when @b < @a  then @b
              WHEN @a IS NULL THEN @b
              WHEN @b IS NULL THEN @a
              else null
         end
END;

Ayrıca bu işlev NULL s postgresql sürümü gibi işler .

Bu işlev kolaylık sağlamak için DB'ye eklenebilir, ancak yerleşik kullanımdan 10 kat daha yavaştırIIF . Testlerim, tam tipte ( datetime ) böyle bir işlevin sql_variant sürümü ile aynı performansı gösterdiğini gösteriyor .

PS 350k değerleri veri seti üzerinde bazı testler yapıyorum ve performans aynı görünüyor, sql_variant biraz daha hızlı, ama ben sadece titremeleri inanıyorum.

Ama herhangi bir şekilde IIF sürümü 10 kat daha hızlı !!!

Satır içi test etmedim CASE WHENama temelde t-sql IIF için durumla aynı ve iif get optimizer tarafından vaka ifadesine dönüştürülür.

IIF'nin CASE'e çevrilmiş olması, bu işlevin davranışının diğer yönleri üzerinde de bir etkiye sahiptir.

SONUÇ: Performans önemliyse, ancak prototipleme için veya kod netliğine daha fazla ihtiyaç duyuluyorsa ve büyük hesaplamalar söz konusu değilse, işlev kullanılabiliyorsa IIF'yi kullanmak daha hızlıdır .


LEAST () ve GREATEST (), bir SQL lehçesinde bulunduğunda, n sütun arasındaki bir satırda karşılaştırmaya izin verir; OP'yi, eşdeğer sonuçlar sağlayacak bir çözümün peşinde koştum. Buradaki cevap (diğerleri ile birlikte) sadece 2'yi desteklemektedir.
Dodecaphone
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.