【问题标题】:Stored Procedure returns different results if executed from Trigger vs Manual如果从触发器与手动执行,存储过程返回不同的结果
【发布时间】:2010-12-03 23:16:14
【问题描述】:

我有一个存储过程,它用另一个表中的数据填充一个表。 当我使用更新触发器执行 SP 3 记录被插入到表中。

如果我手动执行 SP,我会在表中获得 6 条记录。

 'SET ANSI_NULLS ON', 
 'SET QUOTED_IDENTIFIER ON', 
 'SET NOCOUNT ON' 

在 SP 和 Trigger 中是相同的。

这是SP:

 SET ANSI_NULLS ON
 GO
 SET QUOTED_IDENTIFIER ON
 GO
 -- =============================================
 -- Author:     
 -- Create date: 
 -- Description:    
 -- =============================================
 ALTER PROCEDURE [dbo].[Residency_Date_Summary_Populate]
-- Add the parameters for the stored procedure here

 AS
 BEGIN
-- SET NOCOUNT ON added to prevent extra result sets from
-- interfering with SELECT statements.
SET NOCOUNT ON;

 DECLARE @StartDate datetime;
 SET @StartDate = DateAdd(year, DateDiff(year, 0, GetDate()), 0);

 WITH Tally (N) AS 
 (SELECT TOP (12) ROW_NUMBER() OVER (ORDER BY (SELECT 0))
 FROM master.sys.objects), CTE1 AS
 (SELECT c.First_Name,
   c.Last_Name,
   c.ID,
    r.Building,       
   r.Move_In_Date,
   r.Move_Out_Date,
   StartOfMonth = DateAdd(month, t1.N-1, @StartDate),
   EndOfMonth   = DateAdd(day, -1, DateAdd(month, t1.N, @StartDate)),
   MonthNbr = t1.N
 FROM CONTACTS c
   JOIN Residency_Dates r
     ON c.ID = r.ID_U       
   JOIN Tally t1
     ON t1.N between month(r.move_in_date) and month(coalesce( r.move_out_date,        getdate  ()))), CTE2 AS
  ( SELECT First_Name,
   Last_Name,
   Building,
   MonthNbr,
   ID
   ,StayForMonth = CASE WHEN Move_In_Date > StartOfMonth AND Move_out_Date <=      EndOfMonth 
    THEN DateDiff(day, Move_In_Date, Move_Out_Date)
         WHEN Move_In_Date > StartOfMonth 
    THEN DateDiff(day, Move_In_Date, EndOfMonth)
         WHEN Move_out_Date > EndOfMonth 
    THEN DateDiff(day, StartOfMonth, EndOfMonth) 
         WHEN Move_out_Date IS NULL AND month(StartOfMonth) = month(GetDate())
    THEN DateDiff(day, StartOfMonth, GetDate())
         ELSE DateDiff(day, StartOfMonth, COALESCE(Move_Out_Date, EndOfMonth)) 
    END    
 FROM CTE1)
 INSERT into Residency_Date_Summary

 SELECT First_Name,
   Last_Name,
   Building,
   January = MAX(CASE WHEN MonthNbr = 1 THEN StayForMonth ELSE 0 END),
   February = MAX(CASE WHEN MonthNbr = 2 THEN StayForMonth ELSE 0 END),
   March = MAX(CASE WHEN MonthNbr = 3 THEN StayForMonth ELSE 0 END),
   April = MAX(CASE WHEN MonthNbr = 4 THEN StayForMonth ELSE 0 END),
   May = MAX(CASE WHEN MonthNbr = 5 THEN StayForMonth ELSE 0 END),
   June = MAX(CASE WHEN MonthNbr = 6 THEN StayForMonth ELSE 0 END),
   July = MAX(CASE WHEN MonthNbr = 7 THEN StayForMonth ELSE 0 END),
   August = MAX(CASE WHEN MonthNbr = 8 THEN StayForMonth ELSE 0 END),
   September = MAX(CASE WHEN MonthNbr = 9 THEN StayForMonth ELSE 0 END),
   October = MAX(CASE WHEN MonthNbr = 10 THEN StayForMonth ELSE 0 END),
   November = MAX(CASE WHEN MonthNbr = 11 THEN StayForMonth ELSE 0 END),
   December = MAX(CASE WHEN MonthNbr = 12 THEN StayForMonth ELSE 0 END)
 FROM CTE2  
 GROUP BY First_Name, Last_Name, Building
 ORDER BY Last_Name, First_Name, Building;

End

【问题讨论】:

  • 使用的是同一个登录名吗?它对sys.objects 有权限吗?

标签: sql sql-server stored-procedures triggers


【解决方案1】:

问题在于您用于生成数字计数表的代码

WITH Tally (N) AS 
(SELECT TOP (12) ROW_NUMBER() OVER (ORDER BY (SELECT 0)) FROM master.sys.objects)

当我以具有有限权限的用户身份登录时,select * FROM master.sys.objects 仅返回 6 个项目,而以 sa 身份登录时则返回 82 个项目。因此,您的计数表将只有 6 个项目,而不是您在某些登录名下运行时预期的 12 个项目。

坦率地说,您将登录名添加到 sysadmin 组的“修复”是荒谬的。如果另一个登录触发触发器,并且如果您的应用程序存在任何 SQL 注入漏洞,则您仍然会遇到问题,授予登录系统管理员权限将允许攻击者执行几乎任何操作。

你需要做的就是替换

WITH Tally (N) AS 
 (SELECT TOP (12) ROW_NUMBER() OVER (ORDER BY (SELECT 0))
 FROM master.sys.objects), CTE1 AS
 (SELECT c.First_Name,
   c.Last_Name,

WITH E00(N) AS (SELECT 1 UNION ALL SELECT 1),
     E02(N) AS (SELECT 1 FROM E00 a, E00 b),
     E04(N) AS (SELECT 1 FROM E02 a, E02 b),
     Tally (N) AS (SELECT TOP (12) ROW_NUMBER() OVER (ORDER BY (SELECT 0)) FROM E04), 
     CTE1 AS
 (SELECT c.First_Name,
   c.Last_Name,

【讨论】:

  • 对不起,我不太明白你的回答。你是说数据库用户分配的权限太多?
  • @Stan - 不。如果此查询返回的行数少于 12 .返回的行数将取决于权限。
  • @Martin - 感谢您的帮助。我有点明白你在说什么......我的 SQL 经验非常有限,我也没有完全理解你所指的......请多多包涵。如何更正代码以利用您的示例。我已经尝试使用您的示例进行更新,但没有成功。
  • 我不相信您决定使用 master.sys.objects 只是为了创建 12 个数字。而不是十亿更好、更安全、更简单的方法之一。
  • Martin,感谢您对解决方案的清晰解释。我很感激并已实施。
猜你喜欢
  • 2018-06-21
  • 1970-01-01
  • 2016-02-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-06-21
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多