UDF没有给出相同的结果

时间:2018-09-30 13:10:36

标签: sql sql-server tsql triggers user-defined-functions

当我从触发器中执行UDF时,结果不一样

在触发器中执行时,UDF始终返回true

但由于触发原因,结果为true或false

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 

2 个答案:

答案 0 :(得分:0)

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

我不确定您的表和列的含义是什么,但我认为您正在尝试检查某些唯一性。因此,假设您不希望同一Mandat拥有另一个CategorieNumero记录,则最终的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。

答案 1 :(得分:0)

我用过伊凡的解决方案

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