it-swarm.com.de

Unterstützt SQL Server GREATEST und LEAST, wenn nicht, was ist die übliche Problemumgehung?

Überprüfung diese Frage es scheint, dass das eine Menge Arbeit ist, die nicht benötigt werden sollte. Sie versuchen, einen Bereich mit einem Datum zu erweitern. In anderen Datenbanken würden Sie nur greatest und least verwenden.

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

Wenn ich versuche, diese zu verwenden, bekomme ich

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

Das würde die Ausdehnung in beide Richtungen abdecken.

Für die Zwecke der Frage müssten Sie immer noch den exklusiven Bereich ersetzen.

Ich frage mich nur, wie SQL Server-Benutzer Abfragemuster implementieren, um die Funktionen least und greatest nachzuahmen.

Rollen Sie die Bedingungen in CASE -Anweisungen ab oder gibt es eine Erweiterung, ein Add-On eines Drittanbieters oder eine Lizenz von Microsoft, die diese Funktionalität aktiviert?

20
Evan Carroll

Eine übliche Methode ist die Verwendung der Klausel VALUES und CROSS APPLY die beiden Spalten als einzelne Spalte alias, dann erhalten Sie die MIN und MAX von jeder.

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 );

Es gibt andere Möglichkeiten, es zu schreiben, zum Beispiel mit 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);

Das resultierende Abfragepläne scheint jedoch dasselbe zu sein.

33
Erik Darling

Sie können die Werte auch in eine Unterabfrage einfügen. So was:

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

MINDESTENS Äquivalent:

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

GRÖSSTES Äquivalent:

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

Dies wäre ein guter Anfang -

CASE WHEN A > B THEN A ELSE B END
3
Jim Gettma

Ich erstelle benutzerdefinierte Funktionen, z.

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

Obwohl dies in einfachen Fällen funktionieren kann, gibt es bei diesem Ansatz mehrere Probleme:

  • Ärgerlicherweise müssen Sie für jeden Datentyp separate Funktionen erstellen.
  • Es werden nur 2 Parameter verarbeitet, sodass möglicherweise mehr Funktionen erforderlich sind, um viele Parameter zu verarbeiten, oder verschachtelte Aufrufe derselben Funktionen verwenden.
  • Es wäre besser (effizienter) als Inline-TVF als als Skalarfunktion. Das hat mit der Implementierung von Skalarfunktionen im Herzen zu tun. Es gibt viele Blogs darüber, siehe zum Beispiel SQL 101: Parallelism Inhibitors - Scalar User Defined Functions (von John Kehayias .
  • Wenn eines der Argumente null ist, wird null zurückgegeben. Dies entspricht der Funktionsweise des Operators least in Oracle und MySQL, unterscheidet sich jedoch von Postgres. Aber diese Panzerung gegen Null macht es ausführlicher (wenn Sie wissen, dass sie nicht null sind, ein einfaches case when @a <= @b then @a else @b end würde funktionieren).

Alles in allem ist es möglicherweise besser, die Anweisung case mit der Hand zu schreiben, wenn es auf die Leistung ankommt. Ich habe sogar versucht, verschachtelte case -Anweisungen auf der Clientseite zu generieren, wenn mehrere Werte zu vergleichen sind.

0
Ed Avis

Ich hatte vor, der Antwort von @ ed-avis einen Kommentar hinzuzufügen, konnte dies jedoch aufgrund mangelnder Reputation nicht. Daher wurde dies als Erweiterung seiner Antwort veröffentlicht.

Ich habe den Nachteil von "Ärgerlicherweise müssen Sie für jeden Datentyp separate Funktionen erstellen" beseitigt. Verwenden von SQL_VARIANT .

Hier ist meine Implementierung:

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;

Auch diese Funktion behandelt [~ # ~] null [~ # ~] s wie die postgresql-Version.

Diese Funktion könnte der Einfachheit halber zur Datenbank hinzugefügt werden, ist jedoch zehnmal langsamer als die Verwendung von integriertem IIF. Meine Tests zeigen, dass eine solche Funktion mit genauem Typ ( datetime ) dieselbe Leistung erbringt wie sql_variant Ausführung.

PS Ich führe einige Tests mit einem Datensatz von 350.000 Werten durch und scheine die Leistung gleich zu sein. sql_variant ist ein bisschen schneller, aber ich glaube, es ist nur Jitter.

Aber auf jeden Fall ist die IIF-Version 10x mal schneller !!!

Ich habe nicht inline getestet CASE WHEN aber im Grunde genommen für t-sql IIF ist dasselbe wie case und iif wird vom Optimierer in case expression konvertiert.

Die Tatsache, dass IIF in CASE übersetzt wird, wirkt sich auch auf andere Aspekte des Verhaltens dieser Funktion aus.

SCHLUSSFOLGERUNG: Es ist schneller zu verwenden [~ # ~] iif [~ # ~] Wenn die Leistung wichtig ist, aber für das Prototyping oder wenn mehr Codeklarheit erforderlich ist und keine großen Berechnungen erforderlich sind, kann die Funktion verwendet werden.

0
Bogdan Mart