UDF 不给出相同的结果
Posted
技术标签:
【中文标题】UDF 不给出相同的结果【英文标题】:UDF don't give the same result 【发布时间】:2018-09-30 13:10:36 【问题描述】:当我在触发器之外执行 UDF 时结果不一样
在触发器中执行时,UDF 总是返回 true
但在触发器之外结果是真还是假
ALTER FUNCTION [dbo].[MandatExist]
(
@Numero int,
@IdBranche int,
@Exercice int
)
RETURNS bit
AS
BEGIN
DECLARE @Result bit
DECLARE @Nbr int
DECLARE @Categ int
SELECT @Categ = CategorieNumero
FROM Branche
WHERE IdBranche = @IdBranche
SELECT @Nbr=COUNT(*)
FROM Mandat AS M INNER JOIN Branche AS B ON M.IdBranche=B.IdBranche
WHERE (Numero = @Numero) AND (B.CategorieNumero = @Categ) AND (Exercice = @Exercice)
IF @Nbr = 0
SET @Result = 0
ELSE
SET @Result = 1
RETURN @Result
END
触发器调用 MandatExist 来获取号码是否存在
ALTER TRIGGER [dbo].[ValidInsertUpdate_Mandat]
ON [dbo].[Mandat]
FOR INSERT,UPDATE
AS
BEGIN
SET NOCOUNT ON;
DECLARE @Cloturer AS bit
DECLARE @Exercice AS int
DECLARE @IdBranche AS int
DECLARE @Numero AS int
DECLARE @Message AS nvarchar(100)
SELECT @Cloturer=Cloturer, @Exercice=Exercice, @Numero=Numero, @IdBranche=IdBranche
FROM INSERTED
IF (dbo.MandatExist(@Numero, @IdBranche, @Exercice)=1)
BEGIN
SET @Message = 'Numero de mandat existant.'
RAISERROR(@Message, 16, 1)
ROLLBACK TRAN
END
【问题讨论】:
请在问题后面附加 UDF 的定义。 如何从触发器调用 UDF?所述触发器的代码是什么?调用时所述数据的值是多少?我们看不到您看到的内容,因此除非您向我们展示,否则我们无能为力。inserted
和deleted
是表,因此它们可以表示集合操作的结果。假设触发器总是只处理一行,而设计触发器通常是一个糟糕的计划。如果您绝对确定不会超过一排,那么请添加对行数的检查,并使用RaIsError
或Throw
明确告知稍后来的人他们有试图执行不可接受的语句。 (if ( select Count(*) from inserted ) > 1 RaIsError( 'FooTable_Insert: No more than one row may be processed.', 25, 42 ) with log
)
提示:当检查是否存在一行或多行时,使用EXISTS
比获取精确的COUNT
更有效,然后只检查它是否大于零。跨度>
【参考方案1】:
INSERTED
是一个表格,因此可能包含多于一行,这意味着此代码
SELECT @Cloturer=Cloturer, @Exercice=Exercice, @Numero=Numero, @IdBranche=IdBranche
FROM INSERTED
本质上是不正确的。
UDF 不是基于集合的编程的最佳选择,并且可能会导致性能下降。具体来说,这个 UDF 完全没有意义,没有理由将此代码封装到单独的模块中。这是一个简单的EXISTS
代码。
整个函数可以而且必须用EXISTS
语句替换,触发器的整个代码可能如下所示:
IF EXISTS(
SELECT 1
FROM INSERTED
INNER JOIN ...
WHERE ...
)
BEGIN
RAISERROR(...)
END
我不确定您的表格和列的含义是什么,但我假设您正在尝试检查一些唯一性。因此,假设您不希望同一 CategorieNumero
有另一个 Mandat
记录,最终的 EXISTS 可能如下所示:
IF EXISTS(
SELECT 1
FROM INSERTED i
INNER JOIN Branch b on b.IdBranche = i.IdBranch
-- other branches with the same CategorieNumero; why isn't CategorieNumero unique?
INNER JOIN Branch b_dup on b_dup.CategorieNumero = b.CategorieNumero
-- existing Mandat rows for the same CategorieNumero with any IdBranch
INNER JOIN Mandat m_dup on m_dup = b_dup.IdBranch
-- ensure you're not comparing inserted/updated Mandat row to itself
WHERE i.ID != m_dup.ID
)
...
但我不清楚您的意图,我认为在澄清之后,独特的约束将很容易满足您的大部分需求。
如果您不希望每组 (Exercice, Numero, IdBranch)
多出一行 - 只需向 Mandat
表添加唯一约束并删除触发器和函数!
不要过度使用触发器。还有 UDF。
【讨论】:
【参考方案2】:我用过伊万的解决方案
IF EXISTS(
SELECT 1
FROM INSERTED I INNER JOIN Branche b ON b.IdBranche = i.IdBranche
INNER JOIN Branche b_dup ON b_dup.IdBranche = b.IdBranche
INNER JOIN Mandat m_dup on (m_dup.Exercice = i.Exercice) AND (m_dup.Numero = i.Numero) AND (b_dup.IdBranche=i.IdBranche)
WHERE i.IdMandat != m_dup.IdMandat
)
BEGIN
RAISERROR('error', 16, 1)
ROLLBACK TRAN
END
【讨论】:
以上是关于UDF 不给出相同的结果的主要内容,如果未能解决你的问题,请参考以下文章
使用 Matlab FFT 计算的频谱对于不同长度的样本(点数相同但 Fs 不同)给出的结果不一致?