我们可以使用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.
等待你的好主意
答案 0 :(得分:69)
答案 1 :(得分:18)
SQL Server中的函数(如数学中的函数)不能用于修改数据库。它们只是只读的,可以帮助开发人员实现command-query separation。换句话说,提出问题不应该改变答案。当您的程序需要修改数据库时,请使用存储过程。
答案 2 :(得分:11)
是的,你可以!))
我找到了一种使用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
答案 3 :(得分:4)
您无法像存储过程那样更新函数中的表,但可以更新表变量。
例如,你不能在你的函数中执行此操作:
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'
答案 4 :(得分:3)
是,你可以。
但是,它需要具有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)
文档:Modify table state within a SQL Function
免责声明:我是该项目的所有者Eval SQL.NET
答案 5 :(得分:0)
使用 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'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;
答案 6 :(得分:0)
我们不能说在用户定义的函数中执行更新操作不存在其他方式。直接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
答案 7 :(得分:0)
“功能仅具有只读数据库访问权限” 如果在函数中允许DML操作,则函数将类似于存储过程。
答案 8 :(得分:0)
不,您不能执行插入/更新/删除。
函数仅适用于select
语句。而且它只有只读数据库访问权限。
此外:
答案 9 :(得分:0)
您可以将表变量作为返回类型,然后根据该输出对表进行更新或插入。 换句话说,您可以将变量输出设置为原始表,进行修改,然后从函数输出中插入原始表。 这是一个小技巧,但是如果您从原始表中插入@output_table,然后说: 插入my_table 从my_function中选择*
然后您可以实现结果。
答案 10 :(得分:0)
CREATE FUNCTION dbo.UdfGetProductsScrapStatus
(
@ScrapComLevel INT
)
RETURNS @ResultTable TABLE
(
ProductName VARCHAR(50), ScrapQty FLOAT, ScrapReasonDef VARCHAR(100), ScrapStatus VARCHAR(50)
) AS BEGIN
INSERT INTO @ResultTable
SELECT PR.Name, SUM([ScrappedQty]), SC.Name, NULL
FROM [Production].[WorkOrder] AS WO
INNER JOIN
Production.Product AS PR
ON Pr.ProductID = WO.ProductID
INNER JOIN Production.ScrapReason AS SC
ON SC.ScrapReasonID = WO.ScrapReasonID
WHERE WO.ScrapReasonID IS NOT NULL
GROUP BY PR.Name, SC.Name
UPDATE @ResultTable
SET ScrapStatus =
CASE WHEN ScrapQty > @ScrapComLevel THEN 'Critical'
ELSE 'Normal'
END
RETURN
END
答案 11 :(得分:0)
函数不应该以这种方式使用,如果您希望执行数据更改,您可以为此创建一个存储过程。
答案 12 :(得分:-1)
如果您需要运行delete / insert / update,您还可以运行动态语句。即:
declare
@v_dynDelete NVARCHAR(500);
SET @v_dynDelete = 'DELETE some_table;';
EXEC @v_dynDelete