Ответ 1
Нет, вы не можете.
Из электронной документации по 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.
Ожидание вашей хорошей идеи
Нет, вы не можете.
Из электронной документации по SQL Server:
Пользовательские функции не могут использоваться для выполнения действий, которые изменяют состояние базы данных.
Функции в SQL Server, как и в математике, не могут использоваться для изменения базы данных. Они предназначены только для чтения и могут помочь разработчику выполнить разделение командной строки. Другими словами, задавая вопрос, не следует изменять ответ. Когда ваша программа должна изменить базу данных, используйте хранимую процедуру.
Да, вы можете!))
Я нашел один способ сделать INSERT
, UPDATE
или DELETE
в функции с помощью xp_cmdshell
.
Итак, вам нужно просто заменить код внутри переменной @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
Вы не можете обновлять таблицы от функции, как если бы вы хранили процедуру, но вы можете обновлять переменные таблицы.
Так, например, вы не можете сделать это в своей функции:
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'
Да, вы можете.
Однако для этого требуется SQL CLR с разрешением EXTERNAL_ACCESS или UNSAFE и указанием строки подключения. Это явно не рекомендуется.
Например, используя Eval SQL.NET (SQL CLR, который позволяет добавлять синтаксис С# в SQL)
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
Еще одна альтернатива, использующая sp_executesql (тестируется только в SQL 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 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;
Мы не можем сказать, что возможно, что их нет, существует другой способ выполнения операции обновления в пользовательской функции. Непосредственно DML в UDF невозможен.
Ниже Query работает отлично:
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
"Функции имеют доступ только к базе данных READ-ONLY". Если в функциях будут разрешены операции DML, функция будет prety похожа на хранимую процедуру.
Нет, вы не можете сделать Вставить/Обновить/Удалить.
Функции работают только с операторами select
. И он имеет только доступ только для чтения базы данных.
Кроме того:
если вам нужно запустить удаление/вставку/обновление, вы также можете запускать динамические операторы. то есть:.
declare
@v_dynDelete NVARCHAR(500);
SET @v_dynDelete = 'DELETE some_table;';
EXEC @v_dynDelete