SQL Server 过程不返回任何结果

Posted

技术标签:

【中文标题】SQL Server 过程不返回任何结果【英文标题】:SQL Server procedure returning no results 【发布时间】:2012-05-16 15:40:03 【问题描述】:

好的,所以我的 SQL Server 2005 数据库中有以下过程。我试图弄清楚为什么它没有给我任何结果。尝试访问它的用户是管理员,但我也尝试与另一个用户一起访问它,但我仍然没有得到任何结果。 Bond 在对 Bond 表的基本查询中返回。我只是想弄清楚为什么这没有返回任何结果。任何帮助表示赞赏。

ALTER PROCEDURE dbo.GetBondAmounts
(
    @Username varchar(20)
)
AS
DECLARE @Admin AS bit
SELECT @Admin = Admin FROM Users WHERE Username = @Username
if(@Admin = 1)
BEGIN
    RETURN
    SELECT Bond.ID, SUM(Charge.BondAmount) + SUM(ChargeWithoutPower.BondAmount) Amount,
    SUM(Charge.BondPremium) + SUM(ChargeWithoutPower.BondPremium) + SUM(Forfeiture.AmountPaid)
    + SUM(Forfeiture.CostOfApprehension) - SUM(Payment.Amount) - SUM(BalanceForgiveness.AmountForgiven) Balance
    FROM Bond LEFT OUTER JOIN Payment ON Bond.ID = Payment.Bond
    LEFT OUTER JOIN BalanceForgiveness ON Bond.ID = BalanceForgiveness.BondID
    LEFT OUTER JOIN Powers ON Bond.ID = Powers.Bond
    LEFT OUTER JOIN Charge ON Powers.Surety = Charge.PowerSurety
    AND Powers.PowerPrefix = Charge.PowerPrefix AND Powers.PowerNumber = Charge.PowerNumber
    LEFT OUTER JOIN ChargeWithoutPower ON Bond.ID = ChargeWithoutPower.ID
    LEFT OUTER JOIN Forfeiture ON Bond.ID = Forfeiture.Bond
    LEFT OUTER JOIN BondFee ON Bond.ID = BondFee.Bond
    GROUP BY Bond.ID
END
ELSE
BEGIN
    RETURN
    SELECT Bond.ID, SUM(Charge.BondAmount) + SUM(ChargeWithoutPower.BondAmount) Amount,
    SUM(Charge.BondPremium) + SUM(ChargeWithoutPower.BondPremium) + SUM(Forfeiture.AmountPaid)
    + SUM(Forfeiture.CostOfApprehension) - SUM(Payment.Amount) - SUM(BalanceForgiveness.AmountForgiven) Balance
    FROM Bond LEFT OUTER JOIN UserAgency ON Bond.Agency = UserAgency.Agency
    LEFT OUTER JOIN Payment ON Bond.ID = Payment.Bond
    LEFT OUTER JOIN BalanceForgiveness ON Bond.ID = BalanceForgiveness.BondID
    LEFT OUTER JOIN Powers ON Bond.ID = Powers.Bond
    LEFT OUTER JOIN Charge ON Powers.Surety = Charge.PowerSurety
    AND Powers.PowerPrefix = Charge.PowerPrefix AND Powers.PowerNumber = Charge.PowerNumber
    LEFT OUTER JOIN ChargeWithoutPower ON Bond.ID = ChargeWithoutPower.ID
    LEFT OUTER JOIN Forfeiture ON Bond.ID = Forfeiture.Bond
    LEFT OUTER JOIN BondFee ON Bond.ID = BondFee.Bond
    WHERE UserAgency.Username = @Username
    GROUP BY Bond.ID
END

我正在使用 C# 访问此过程,如下所示:

bondingData.Merge(getBondAmountsAdapter.GetData(currentUser.Username));

这是我添加的行来测试并查看是否返回任何结果:

MessageBox.Show("Bond Count A: " + bondingData.Bond.Count.ToString() + "\r\nBond Count B: " + bondingData.GetBondAmounts.Count.ToString());

当我运行它时,这是我收到的结果:

Bond Count A: 1
Bond Count B: 0

[编辑]

好的,这是我的问题的解决方案:

ALTER PROCEDURE dbo.GetBondAmounts
(
    @Username varchar(20)
)
AS
    SELECT Bond.ID, dbo.GetBondTotal(Bond.ID) Total, dbo.GetBondBalance(Bond.ID) Balance
    FROM Bond LEFT OUTER JOIN
    UserAgency ON Bond.Agency = UserAgency.Agency
    WHERE UserAgency.Username = @Username
    OR EXISTS (SELECT * FROM Users WHERE Username = @Username AND Admin = 1)
    GROUP BY Bond.ID

这些是此处调用的 2 个存储函数。不确定它的效率如何,但不会有那么多付款或与单个债券相关的任何事情。当程序有很多记录时,它可能会变慢。

功能1:

ALTER FUNCTION dbo.GetBondTotal
(
@BondID bigint
)
RETURNS money
AS
BEGIN
    DECLARE @PowersTotal AS money;
    DECLARE @ChargesTotal AS money;
    DECLARE @BondFeeTotal AS money;
    DECLARE @ForfeitureCosts AS money;
    SELECT @PowersTotal = SUM(BondPremium)
    FROM Charge INNER JOIN Powers ON Charge.PowerSurety = Powers.Surety
    AND Charge.PowerPrefix = Powers.PowerPrefix
    AND Charge.PowerNumber = Powers.PowerNumber
    WHERE Bond = @BondID
    SELECT @ChargesTotal = SUM(BondPremium)
    FROM ChargeWithoutPower
    WHERE BondID = @BondID
    SELECT @BondFeeTotal = SUM(Amount)
    FROM BondFee WHERE Bond = @BondID
    SELECT @ForfeitureCosts = SUM(CostOfApprehension) + SUM(AmountPaid)
    FROM Forfeiture WHERE Bond = @BondID
    RETURN @PowersTotal + @ChargesTotal + @BondFeeTotal + @ForfeitureCosts
END

功能2:

ALTER FUNCTION dbo.GetBondBalance
(
@BondID bigint
)
RETURNS MONEY
AS
    BEGIN
    DECLARE @PowersTotal AS money;
    DECLARE @ChargesTotal AS money;
    DECLARE @BondFeeTotal AS money;
    DECLARE @ForfeitureCosts AS money;
    DECLARE @PaymentTotal AS money;
    DECLARE @AmountForgiven AS money;
    SELECT @PowersTotal = SUM(BondPremium)
    FROM Charge INNER JOIN Powers ON Charge.PowerSurety = Powers.Surety
    AND Charge.PowerPrefix = Powers.PowerPrefix
    AND Charge.PowerNumber = Powers.PowerNumber
    WHERE Bond = @BondID
    SELECT @ChargesTotal = SUM(BondPremium)
    FROM ChargeWithoutPower
    WHERE BondID = @BondID
    SELECT @BondFeeTotal = SUM(Amount)
    FROM BondFee WHERE Bond = @BondID
    SELECT @ForfeitureCosts = SUM(CostOfApprehension) + SUM(AmountPaid)
    FROM Forfeiture WHERE Bond = @BondID
    SELECT @PaymentTotal = SUM(Amount)
    FROM Payment WHERE Bond = @BondID
    SELECT @AmountForgiven = SUM(AmountForgiven)
    FROM BalanceForgiveness WHERE BondID = @BondID
    RETURN @PowersTotal + @ChargesTotal + @BondFeeTotal + @ForfeitureCosts - @PaymentTotal - @AmountForgiven
END

我相信我会创建第三个函数来覆盖金额(Charge.Amount + ChargeWithoutPower.Amount)

【问题讨论】:

【参考方案1】:

您在每个部分的开头都有一个RETURN 声明。

一旦命中该语句,查询将立即返回,因此SELECT 不会执行,也不会返回任何内容。

要解决此问题 - 删除 RETURN 语句。

【讨论】:

【参考方案2】:

我怀疑您认为该过程需要返回结果集。事实上,程序只能“返回”一个整数。它们可以设置输出参数,任何被选择的结果集都会被放入输出流中,但它们与 RETURN 语句没有任何关系。

另请注意,您的第二个查询 WHERE 子句有效地将第一个 LEFT JOIN 转换为 INNER JOIN。

您可以将这两个查询组合成一个查询,这可能更易于维护,并且您可以消除对单独的位变量和管理查询的需要。请注意,组合版本更易于维护,但可能有一个次优的执行计划,因为这两种情况可能需要非常不同的执行计划。它也可能容易受到参数嗅探的影响,因此您可能希望使用“优化未知”选项和/或将它们分成两部分 - 这是一种权衡。很多时候,当我看到在一个地方可能更容易维护的重复代码时,我不得不权衡一下。有时重复的连接可以变成视图或内联表值函数。

我认为它可以简化为:

ALTER PROCEDURE dbo.GetBondAmounts
(
    @Username varchar(20)
)
AS
BEGIN
    SELECT Bond.ID
           ,SUM(Charge.BondAmount)
             + SUM(ChargeWithoutPower.BondAmount) AS Amount
           ,SUM(Charge.BondPremium)
             + SUM(ChargeWithoutPower.BondPremium)
             + SUM(Forfeiture.AmountPaid)
             + SUM(Forfeiture.CostOfApprehension)
             - SUM(Payment.Amount)
             - SUM(BalanceForgiveness.AmountForgiven) AS Balance
    FROM Bond
    LEFT OUTER JOIN UserAgency ON Bond.Agency = UserAgency.Agency
    LEFT OUTER JOIN Payment ON Bond.ID = Payment.Bond
    LEFT OUTER JOIN BalanceForgiveness ON Bond.ID = BalanceForgiveness.BondID
    LEFT OUTER JOIN Powers ON Bond.ID = Powers.Bond
    LEFT OUTER JOIN Charge ON Powers.Surety = Charge.PowerSurety
        AND Powers.PowerPrefix = Charge.PowerPrefix
        AND Powers.PowerNumber = Charge.PowerNumber
    LEFT OUTER JOIN ChargeWithoutPower ON Bond.ID = ChargeWithoutPower.ID
    LEFT OUTER JOIN Forfeiture ON Bond.ID = Forfeiture.Bond
    LEFT OUTER JOIN BondFee ON Bond.ID = BondFee.Bond
    WHERE UserAgency.Username = @Username
        OR EXISTS (SELECT * FROM Users WHERE Username = @Username AND Admin = 1)
    GROUP BY Bond.ID
END

(请注意,在简化的时候,我会强烈考虑使用内联表值函数而不是过程,它类似于参数化视图,比存储过程更灵活)

你分组和加入的方式让我有点担心。

如果您有多个付款和没收(或任何其他通过 Bond.ID 链接的表)附加到一个债券,那么您将得到一个无意的交叉连接,将这些值相乘然后相加,得到不正确的结果。

我怀疑您需要做这样的事情来进行分组 - 请注意,我已经在子查询中完成了分组并用相同的名称重新命名了它们:

ALTER PROCEDURE dbo.GetBondAmounts
(
    @Username varchar(20)
)
AS
BEGIN
    SELECT Bond.ID
           ,Charge.BondAmount
             + ChargeWithoutPower.BondAmount AS Amount
           ,Charge.BondPremium
             + ChargeWithoutPower.BondPremium
             + Forfeiture.AmountPaid
             + Forfeiture.CostOfApprehension
             - Payment.Amount
             - BalanceForgiveness.AmountForgiven AS Balance
    FROM Bond
    LEFT OUTER JOIN UserAgency ON Bond.Agency = UserAgency.Agency
    LEFT OUTER JOIN (
        SELECT Bond, SUM(Amount) AS Amount
        FROM Payment
        GROUP BY Bond
    ) AS Payment ON Bond.ID = Payment.Bond
    --- etc..
    WHERE UserAgency.Username = @Username
        OR EXISTS (SELECT * FROM Users WHERE Username = @Username AND Admin = 1)
END

【讨论】:

一些债券将有多次付款、费用、权力、收费等。我如何才能在没有任何错误的情况下尽快获得所有债券记录的总额和余额(最好在单个查询)?顺便说一句,谢谢您向我展示了如何将这两个语句合并为一个。这很有帮助。 也感谢您密切关注并发现我的代码的另一个问题。 @stickybear13 查看一种技术的编辑 - 您还可以在***别使用标量子查询 这里的这个选项怎么样...我已经有了这些存储的函数,我从我的 C# 代码中调用它们:code SELECT Bond.ID, dbo.GetBondTotal(Bond.ID) Total, dbo.GetBondBalance(Bond.ID) Balance FROM Bond LEFT OUTER JOIN UserAgency ON Bond.Agency = UserAgency.Agency WHERE UserAgency.Username = @Username OR EXISTS (SELECT * FROM Users WHERE Username = @Username AND Admin = 1) GROUP BY Bond.ID @stickybear13 如果你想要一些普遍接受的效率水平,我会重新考虑这种方法——那些标量函数并不是一个很好的设计。我会考虑在这些函数之前使用和加入按债券 ID 分组的每个事务表的摘要视图。

以上是关于SQL Server 过程不返回任何结果的主要内容,如果未能解决你的问题,请参考以下文章

将@@ rowcount分配给SQL Server存储过程中的变量

SQL Server存储过程同时返回分页结果集和总数

在 sql 适配器过程中使用 WL.Server.invokeSQLStatement 返回的结果集

从存储过程执行 SQL Server 代理作业并返回作业结果

SQL Server / T-SQL:CHOOSE是评估所有结果,还是只返回返回的结果?

SQL SERVER里面如何在存储过程里面获取另一个存储过程所返回的表的数据?