web-dev-qa-db-ja.com

SQL ServerはGREATESTとLEASTをサポートしていますか?

復習 この質問 必要のない多くの作業のようです。彼らは日付で範囲を拡張しようとしています。他のデータベースでは、greatestleast。を使用するだけです。

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

これらを使用しようとすると、

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

それはどちらの方向への拡張もカバーします。

質問の目的のために、あなたはまだ排他的な範囲交換をしなければならないでしょう。

SQL Serverユーザーがleastgreatestの機能を模倣するクエリパターンをどのように実装するのか疑問に思っています。

条件をCASEステートメントに展開しますか、またはこの機能を有効にする拡張機能、サードパーティのアドオン、またはMicrosoftからのライセンスがありますか?

20
Evan Carroll

一般的な方法の1つは、VALUES句とCROSS APPLYを使用して、2つの列を単一の列としてエイリアス化し、それぞれのMINMAXを取得することです。

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

たとえば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);

ただし、結果の クエリプラン は同じように見えます。

33
Erik Darling

値をサブクエリにインラインで配置することもできます。このような:

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

LEAST相当:

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

GREATEST相当:

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

これは良いスタートです-

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

ユーザー定義関数を作成します。

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

単純なケースでも機能する可能性がありますが、このアプローチにはいくつかの問題があります。

  • 厄介なことに、データ型ごとに個別の関数を作成する必要があります。
  • 2つのパラメーターのみを処理するため、多くのパラメーターを処理したり、同じ関数のネストされた呼び出しを使用したりするには、さらに関数が必要になる場合があります。
  • スカラー関数よりもインラインTVFのほうが(効率的)です。これは、スカラー関数の実装に関係しています。それについては多くのブログがあります。たとえば SQL 101:Parallelism Inhibitors – Scalar User Defined Functions(by John Kehayias )を参照してください。
  • 引数の1つがnullの場合、nullを返します。これは、OracleおよびMySQLでのleast演算子の動作と一致しますが、Postgresとは異なります。しかし、nullに対するこの防御は、より冗長になります(nullにならないことがわかっている場合は、単純なcase when @a <= @b then @a else @b endは機能します)。

全体として、パフォーマンスが重要な場合は、caseステートメントを長文で記述する方がよい場合があります。比較する値がいくつかある場合は、クライアント側でネストされたcaseステートメントを生成することにも頼りました。

0
Ed Avis

私は@ ed-avisの回答にコメントを追加するつもりでしたが、評判が足りなかったため追加できませんでした。そのため、彼の回答の拡張としてこれを投稿します。

「面倒なことに、データ型ごとに別々の関数を作成する必要がある」という欠点を排除しました。 SQL_VARIANTを使用します。

これが私の実装です:

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;

また、この関数はpostgresqlバージョンのように[〜#〜] null [〜#〜]を処理します。

この関数は、便宜上DBに追加できますが、組み込みのIIFを使用するよりも10倍遅くなります。私のテストは、正確なタイプ(datetime)を持つ関数がsql_variantバージョンと同じように機能することを示しています。

PS350k値のデータセットに対していくつかのテストを実行し、パフォーマンスは同じであるようですが、sql_variantは少し高速です、しかしそれは単なるジッターだと思います。

しかし、IIFバージョンは10x倍高速です。

インラインでテストしていませんCASE WHENですが、基本的にt-sqlの場合 IIFはcaseと同じです 、およびiifはオプティマイザによってcase式に変換されます。

IIFがCASEに変換されるという事実は、この関数の動作の他の側面にも影響を与えます。

結論:パフォーマンスが重要である場合はプロトタイピングのため、または[〜#〜] iif [〜#〜]を使用する方が速いコードの明快さがさらに必要で、大きな計算が含まれていない場合は、提供された関数を使用できます。

0
Bogdan Mart