私は長い間関数とストアドプロシージャを学んできましたが、なぜ私が関数やストアドプロシージャを使うべきなのか、そしていつ使うべきかわかりません。彼らは私には同じに見えます、おそらく私はそれについてちょっと初心者だからです。
誰かが私にその理由を教えてもらえますか?
関数は計算値であり、SQL Serverに対して永続的な環境変更を実行することはできません(つまり、INSERTステートメントまたはUPDATEステートメントは許可されていません)。
関数は、スカラー値を返す場合はSQLステートメント内でインラインで使用することができ、結果セットを返す場合は結合することができます。
答えを要約したコメントから注目に値するポイント。 @Sean K Andersonに感謝します:
関数は、値を返さなければならず、パラメータとして受け取るデータ(引数)を変更することはできないという点で、コンピュータ科学的定義に従います。関数は何も変更することはできず、少なくとも1つのパラメータを持ち、値を返さなければなりません。ストアドプロシージャはパラメータを持つ必要はなく、データベースオブジェクトを変更することも、値を返す必要もありません。
SPとUDFの違いは以下のとおりです。
+---------------------------------+----------------------------------------+
| Stored Procedure (SP) | Function (UDF - User Defined |
| | Function) |
+---------------------------------+----------------------------------------+
| SP can return zero , single or | Function must return a single value |
| multiple values. | (which may be a scalar or a table). |
+---------------------------------+----------------------------------------+
| We can use transaction in SP. | We can't use transaction in UDF. |
+---------------------------------+----------------------------------------+
| SP can have input/output | Only input parameter. |
| parameter. | |
+---------------------------------+----------------------------------------+
| We can call function from SP. | We can't call SP from function. |
+---------------------------------+----------------------------------------+
| We can't use SP in SELECT/ | We can use UDF in SELECT/ WHERE/ |
| WHERE/ HAVING statement. | HAVING statement. |
+---------------------------------+----------------------------------------+
| We can use exception handling | We can't use Try-Catch block in UDF. |
| using Try-Catch block in SP. | |
+---------------------------------+----------------------------------------+
関数とストアドプロシージャは別々の目的を果たします。最もよく似ているわけではありませんが、関数は文字通り他のどのプログラミング言語でも使用できる関数と見なすことができますが、ストアドプロシージャは個々のプログラムやバッチスクリプトのようなものです。
関数は通常出力を持ち、オプションで入力を持ちます。その出力は、別の関数(DATEDIFF、LENなどのSQL Server組み込み)への入力として、またはSQL Queryへの述語(SELECT a, b, dbo.MyFunction(c) FROM table
やSELECT a, b, c FROM table WHERE a = dbo.MyFunc(c)
など)として使用できます。
ストアドプロシージャは、トランザクション内でSQLクエリをバインドし、外部とのインタフェースをとるために使用されます。 ADO.NETなどのフレームワークは関数を直接呼び出すことはできませんが、ストアドプロシージャを直接呼び出すことはできます。
ただし、関数には隠された危険性があります。それらは誤用され、かなり厄介なパフォーマンスの問題を引き起こす可能性があります。このクエリを考慮してください。
SELECT * FROM dbo.MyTable WHERE col1 = dbo.MyFunction(col2)
MyFunctionは次のように宣言されています。
CREATE FUNCTION MyFunction (@someValue INTEGER) RETURNS INTEGER
AS
BEGIN
DECLARE @retval INTEGER
SELECT localValue
FROM dbo.localToNationalMapTable
WHERE nationalValue = @someValue
RETURN @retval
END
ここで起こることは、関数MyFunctionがテーブルMyTable内のすべての行に対して呼び出されることです。 MyTableに1000行ある場合、それはデータベースに対する別の1000回のアドホッククエリです。同様に、関数がcolumn specで指定されているときに呼び出されると、SELECTによって返される各行に対して関数が呼び出されます。
だからあなたは注意深く関数を書く必要があります。関数内のテーブルからSELECTを実行する場合は、親ストアドプロシージャ内のJOINまたは他のSQL構造体(CASE ... WHEN ... ELSEなど)を使用したほうが適切に実行できるかどうかを確認する必要があります。終わり)。
他のSQLステートメントで使用するために値を計算して返したい場合は、ユーザー定義関数を作成してください。代わりにストアドプロシージャを作成するのであれば、代わりに複雑なSQLステートメントのセットをグループ化します。結局、これらはまったく異なる2つのユースケースです。
ストアドプロシージャとユーザー定義関数の違い
RAISEERROR
OR @@ERROR
は、UDFでは許可されていません。GETDATE()
はUDFでは使用できません。 STORE PROCEDURE FUNCTION (USER DEFINED FUNCTION)
* Procedure can return 0, single or | * Function can return only single value
multiple values. |
|
* Procedure can have input, output | * Function can have only input
parameters. | parameters.
|
* Procedure cannot be called from | * Functions can be called from
function. | procedure.
|
* Procedure allows select as well as | * Function allows only select statement
DML statement in it. | in it.
|
* Exception can be handled by | * Try-catch block cannot be used in a
try-catch block in a procedure. | function.
|
* We can go for transaction management| * We can't go for transaction
in procedure. | management in function.
|
* Procedure cannot be utilized in a | * Function can be embedded in a select
select statement | statement.
|
* Procedure can affect the state | * Function can not affect the state
of database means it can perform | of database means it can not
CRUD operation on database. | perform CRUD operation on
| database.
|
* Procedure can use temporary tables. | * Function can not use
| temporary tables.
|
* Procedure can alter the server | * Function can not alter the
environment parameters. | environment parameters.
|
* Procedure can use when we want | * Function can use when we want
instead is to group a possibly- | to compute and return a value
complex set of SQL statements. | for use in other SQL
statements.
基本的な違い
関数は値を返さなければなりませんが、ストアドプロシージャではオプションです(プロシージャはゼロまたはn個の値を返すことができます)。
手続きは入力/出力パラメータを持つことができるのに対し、関数はそれに対する入力パラメータのみを持つことができます。
関数は必須の入力パラメータを1つ取りますが、ストアード・プロシージャーはoからn個の入力パラメーターを取ります。
関数はProcedureから呼び出すことができますが、ProcedureはFunctionから呼び出すことはできません。
事前差異
手続きはその中にDML(INSERT/UPDATE/DELETE)文と同様にSELECTを許しますが、関数はその中にSELECT文だけを許します。
手続きはSELECT文の中では利用できませんが、関数はSELECT文の中に埋め込むことができます。
ストアドプロシージャは、WHERE/HAVING/SELECTセクション内のどこにあってもSQLステートメント内で使用することはできませんが、関数は使用できます。
テーブルを返す関数は別の行セットとして扱うことができます。これは他のテーブルとのJOINで使用できます。
インライン関数は、パラメータを取るビューとしても使用でき、JOINや他のRowset操作で使用できます。
Procedureのtry-catchブロックで例外を処理できますが、Functionのtry-catchブロックは使用できません。
手続きでトランザクション管理に進むことができますが、機能に入ることはできません。
ユーザー定義関数は、SQL Serverプログラマーが利用できる重要なツールです。あなたはそのようにSQL文の中でそれをインラインで使うことができます
SELECT a, lookupValue(b), c FROM customers
lookupValue
はUDFになります。この種の機能は、ストアドプロシージャを使用している場合は不可能です。同時に、UDFの内部では特定のことができません。ここで覚えておくべき基本的なことは、UDFのことです。
ストアドプロシージャはそれらのことができます。
私にとって、UDFのインライン使用はUDFの最も重要な使用法です。
ストアドプロシージャ はスクリプトとして使用されます 。彼らはあなたのために一連のコマンドを実行し、あなたはそれらが特定の時間に実行されるようにスケジュールすることができます。
関数 をメソッドとして使用します。 あなたはそれを何か渡すと結果を返します。小さくて速いはず - それはその場で行います。
ストアドプロシージャ:
EXEC
またはEXECUTE
ステートメントを使用して呼び出す必要があります。OUT
パラメータは使用できません。関数:
レコードを選択するためにのみ使用できます。ただし、次のように標準SQLから非常に簡単に呼び出すことができます。
SELECT dbo.functionname('Parameter1')
または
SELECT Name, dbo.Functionname('Parameter1') FROM sysObjects
単純で再利用可能な選択操作のために、関数はコードを単純化することができます。関数内でJOIN
句を使用することには十分注意してください。関数にJOIN
句があり、複数の結果を返す別のselect文からそれを呼び出すと、その関数呼び出しは、結果セットに返される each 行に対して、それらのテーブルをまとめてJOIN
します。そのため、ロジックを単純化するのに役立ちますが、正しく使用されていないとパフォーマンスのボトルネックになる可能性もあります。
OUT
パラメータを使用して値を返します。カーソルなどのSQL Server関数は、最後の武器として使用することを目的としています。これらはパフォーマンスの問題を抱えているので、テーブル値関数の使用はできるだけ避けるべきです。パフォーマンスについて話すのは、ミドルクラスのハードウェア上のサーバーでホストされている1,000,000を超えるレコードを持つテーブルについての話です。それ以外の場合は、機能によるパフォーマンスの低下について心配する必要はありません。
詳細については、以下を参照してください。 http://databases.aspfaq.com/database/should-i-use-a-view-a-stored-procedure-or-a-user-defined-function.html
次の点が役立つ可能性があるものをいつ使用するかを決定するには、
ストアドプロシージャは、関数がそれを実行できる場所でテーブル変数を返すことはできません。
ストアドプロシージャを使用して、サーバー環境パラメータを変更できます。ただし、関数を使用している場合はできません。
乾杯
単一の値を返す関数から始めます。いいことに、よく使うコードを関数に入れて、結果セットの列として返すことができます。
それから、あなたは都市のパラメータ化されたリストのために関数を使うかもしれません。 dbo.GetCitiesIn( "NY")結合として使用できるテーブルを返します。
それはコードを体系化する方法です。何が再利用可能でいつそれが時間の浪費であるかを知ることは、試行錯誤と経験を通してしか得られないものです。
また、関数はSQL Serverでは優れたアイデアです。それらはより速く、そしてかなり強力になり得る。インライン選択と直接選択使いすぎないように注意してください。
これがストアドプロシージャよりも関数を好む実際的な理由です。別のストアドプロシージャの結果を必要とするストアドプロシージャがある場合は、insert-exec文を使用する必要があります。つまり、一時テーブルを作成し、exec
ステートメントを使用してストアドプロシージャの結果を一時テーブルに挿入する必要があります。めちゃくちゃです。これに関する1つの問題は insert-execsを入れ子にすることができないということです 。
他のストアドプロシージャを呼び出すストアドプロシージャを使用している場合は、これに遭遇する可能性があります。入れ子になったストアドプロシージャが単純にデータセットを返す場合は、テーブル値関数に置き換えることができ、このエラーは発生しなくなります。
( これは、ビジネスロジックをデータベースから除外するもう1つの理由です )
手続きでは不可能なところでは、関数はselect文で使用できます。
ストアドプロシージャは入力パラメータと出力パラメータの両方を取りますが、関数は入力パラメータのみを取ります。
手続きができるところでは、関数はtext、ntext、image&timestamps型の値を返すことができません。
関数はcreate tableでユーザ定義データ型として使用できますが、プロシージャは使用できません。
***例:table <tablename>(name varchar(10),salary getsal(name))
を作成する
ここでgetsalはテーブルが作成されたときに給与タイプに割り当てられたストレージが割り当てられていない、そしてgetal関数も実行されない、ユーザ定義関数です。しかし、このテーブルからいくつかの値を取得しているとき戻り値Typeが結果セットとして返されます。
これは非常に古い質問であることを私は認識していますが、私は答えのどれにも言及されている1つの重要な側面を見ません:問い合わせ計画へのインライン化。
機能はすることができます...
スカラー:
CREATE FUNCTION ... RETURNS scalar_type AS BEGIN ... END
複数ステートメントの表値:
CREATE FUNCTION ... RETURNS @r TABLE(...) AS BEGIN ... END
インラインテーブル値:
CREATE FUNCTION ... RETURNS TABLE AS RETURN SELECT ...
3番目の種類(インラインテーブル値)は、クエリオプティマイザによって本質的に(パラメータ化された)ビューとして扱われます。つまり、クエリから関数を参照することは、(実際にはコピー貼り付けせずに)以下の利点があります。
上記のことは、特に複数レベルの機能を組み合わせる場合に、潜在的に著しいパフォーマンスの節約につながる可能性があります。
注:SQL Server 2019では、何らかの形式の スカラー関数のインライン展開 が導入される予定です。
ユーザー定義関数
ストアドプロシージャ