web-dev-qa-db-ja.com

SQL Serverの関数で挿入/更新/削除

Insert/Update/DeleteステートメントとSQL Server Functions。試しましたが、SQL Serverエラーが発生しました。

エラー:

Invalid use of side-effecting or time-dependent operator in 'DELETE' within a function.

AnyBodyには、使用できない理由Insert/Update/DeleteステートメントとSQL Server functions.

あなたの良いアイデアを待っています

36
Pankaj Agarwal

いいえ、できません。

SQL Server Books Onlineから:

ユーザー定義関数を使用して、データベースの状態を変更するアクションを実行することはできません。

参照

70
Mitch Wheat

SQL Serverの関数は、数学のように、データベースを変更するために使用できません。これらは読み取り専用であり、開発者が コマンドとクエリの分離 を実装するのに役立ちます。言い換えれば、質問をしても答えは変わらないはずです。プログラムでデータベースを変更する必要がある場合は、代わりにストアドプロシージャを使用します。

18
Anthony Faull

はい、できます!))

xp_cmdshellを使用して、関数でINSERTUPDATE、またはDELETEを作成する1つの方法を見つけました。

そのため、@ sql変数内のコードを置き換えるだけです。

CREATE FUNCTION [dbo].[_tmp_func](@orderID NVARCHAR(50))
RETURNS INT
AS
BEGIN
DECLARE @sql varchar(4000), @cmd varchar(4000)
SELECT @sql = 'INSERT INTO _ord (ord_Code) VALUES (''' + @orderID + ''') '
SELECT @cmd = 'sqlcmd -S ' + @@servername +
              ' -d ' + db_name() + ' -Q "' + @sql + '"'
EXEC master..xp_cmdshell @cmd, 'no_output'
RETURN 1
END
11
Yurii Tsurul

ストアドプロシージャのように関数からテーブルを更新することはできませんが、テーブル変数を更新できます。

したがって、たとえば、あなたの関数でこれを行うことはできません:

create table MyTable
(
    ID int,
    column1 varchar(100)
)
update [MyTable]
set column1='My value'

しかし、あなたはできる:

declare @myTable table
(
    ID int,
    column1 varchar(100)
)

Update @myTable
set column1='My value'
5
FistOfFury

はい、できます。

ただし、EXTERNAL_ACCESSまたはUNSAFE権限を持ち、接続文字列を指定するSQL CLRが必要です。これは明らかに推奨されません

たとえば、 Eval SQL.NET (SQLでC#構文を追加できるSQL CLR)を使用します。

CREATE FUNCTION [dbo].[fn_modify_table_state]
    (
      @conn VARCHAR(8000) ,
      @sql VARCHAR(8000)
    )
RETURNS INT
AS
    BEGIN
        RETURN SQLNET::New('
using(var connection = new SqlConnection(conn))
{
    connection.Open();

    using(var command = new SqlCommand(sql, connection))
    {
        return command.ExecuteNonQuery();
    }
}
').ValueString('conn', @conn).ValueString('sql', @sql).EvalReadAccessInt()

    END

    GO

DECLARE @conn VARCHAR(8000) = 'Data Source=XPS8700;Initial Catalog=SqlServerEval_Debug;Integrated Security=True'
DECLARE @sql VARCHAR(8000) = 'UPDATE [Table_1] SET Value = -1 WHERE Name = ''zzz'''

DECLARE @rowAffecteds INT =  dbo.fn_modify_table_state(@conn, @sql)

ドキュメント: SQL関数内のテーブル状態の変更

免責事項:私はプロジェクトの所有者です Eval SQL.NET

3
Jonathan Magnan

いいえ、挿入/更新/削除はできません。

関数はselectステートメントでのみ機能します。また、読み取り専用のデータベースアクセスのみがあります。

さらに:

  • 関数は毎回コンパイルします。
  • 関数は値または結果を返す必要があります。
  • 関数は入力パラメーターでのみ機能します。
  • Tryおよびcatchステートメントは関数では使用されません。
0
Majedur Rahaman

「関数には読み取り専用のデータベースアクセスのみがあります」関数でDML操作が許可される場合、関数はストアドプロシージャと同様に機能します。

0
user11378203

sp_executesqlSQL 2016でのみテスト済み)を使用した別の代替手段。以前の投稿が気づいたように、原子性は他の場所で処理する必要があります。

CREATE FUNCTION [dbo].[fn_get_service_version_checksum2]
(
    @ServiceId INT
)
RETURNS INT
AS
BEGIN
DECLARE @Checksum INT;
SELECT @Checksum = dbo.fn_get_service_version(@ServiceId);
DECLARE @LatestVersion INT = (SELECT MAX(ServiceVersion) FROM [ServiceVersion] WHERE ServiceId = @ServiceId);
-- Check whether the current version already exists and that it's the latest version.
IF EXISTS(SELECT TOP 1 1 FROM [ServiceVersion] WHERE ServiceId = @ServiceId AND [Checksum] = @Checksum AND ServiceVersion = @LatestVersion)
    RETURN @LatestVersion;
-- Insert the new version to the table.
EXEC sp_executesql N'
INSERT INTO [ServiceVersion] (ServiceId, ServiceVersion, [Checksum], [Timestamp])
VALUES (@ServiceId, @LatestVersion + 1, @Checksum, GETUTCDATE());',
N'@ServiceId INT = NULL, @LatestVersion INT = NULL, @Checksum INT = NULL',
@ServiceId = @ServiceId,
@LatestVersion = @LatestVersion,
@Checksum = @Checksum
;
RETURN @LatestVersion + 1;
END;
0
Vinicius

ユーザー定義関数で更新操作を実行する他の方法が存在しない可能性があるとは言えません。直接DMLはUDFでは不可能です。

以下のクエリは完全に機能しています。

create table testTbl
(
id int identity(1,1) Not null,
name nvarchar(100)
)
GO

insert into testTbl values('ajay'),('amit'),('akhil')
Go

create function tblValued()
returns Table
as
return (select * from testTbl where id = 1)
Go

update tblValued() set name ='ajay sharma' where id = 1
Go

select * from testTbl 
Go
0
Ajay Sharma