SQL存储过程问题 - 十进制值转换问题

时间:2010-08-05 21:10:50

标签: sql sql-server

我在SQL Server存储过程中遇到了一个非常奇怪的问题。

我有两个数据库。一个包含我的计费系统的数据库。另一种是具有汇总数据的报告系统。在此数据库中,有一个包含汇总作业信息的表。创建此数据时,其中一个字段BilledToDate为null。我编写了一个存储过程,创建一个遍历此表的游标并获取所有作业号。然后,我查看每个工作号码并对计费数据库运行查询,以获得已根据工作收取的计费总额。获得此总数后,我将使用此值更新BilledToDate列。

问题是运行存储过程后,某些结果是正确的,有些则不是。似乎没有任何合理的解释为什么一个是正确的而下一个是不对的。我在存储过程中放了一些print语句,所有值都是正确的。例如,对于一条记录,正确的总和为99,218.25,但更新将值14,700.70放入BilledToDate字段。我在表中添加了一个varchar列并填充了该字段。他们都是正确的。这让我相信它是一个投射问题,但我检查并仔细检查了我的数据类型,它们看起来都是正确的。我正在把这头发拉出来(剩下的东西)。

我的存储过程如下。 InvoiceAmt字段是invchead表中的小数(16,2),我在整个过程中保持一致,所以我不承认为什么会发生这种情况。

ALTER PROCEDURE [dbo].[sp_CalculateBilledToDate] 
AS
BEGIN
 -- SET NOCOUNT ON added to prevent extra result sets from
 -- interfering with SELECT statements.
 SET NOCOUNT ON;

    DECLARE @JobID varchar(10)
    DECLARE @RecordID int
    DECLARE @BilledToDate decimal(16,2)

    DECLARE c1 CURSOR FOR
    SELECT JobID, RecordID
    FROM StructuralOpenBilling

    OPEN c1

    FETCH NEXT FROM c1
    INTO @JobID, @RecordID

    WHILE @@FETCH_STATUS = 0
    BEGIN
        SELECT @BilledToDate = CONVERT(money, CASE WHEN SUM(invoiceamt) > 0 THEN SUM(InvoiceAmt) ELSE 0 END)
        FROM mfgsys803.dbo.invchead
        WHERE shortchar01 = RTRIM(@JobID)

        PRINT 'Record ID: ' + CONVERT(varchar(10), @RecordID) + '  JobID: ' + RTRIM(CONVERT(varchar(10), @JobID)) + '  Billed: ' + CONVERT(varchar(10), @BilledToDate)

        UPDATE StructuralOpenBilling
        SET BilledToDate = @BilledToDate, BilledCheck = CONVERT(varchar(50), @BilledToDate)
        WHERE RecordID = @RecordID

        PRINT 'Record ID: ' + CONVERT(varchar(10), @RecordID) + '  JobID: ' + RTRIM(CONVERT(varchar(10), @JobID)) + '  Billed: ' + CONVERT(varchar(10), @BilledToDate)

        FETCH NEXT FROM c1
        INTO @JobID, @RecordID
    END

    CLOSE c1
    DEALLOCATE c1

END

任何想法都会受到赞赏。

感谢。

约翰

2 个答案:

答案 0 :(得分:2)

我注意到你可能会看到的一些事情。顺便说一句 - 你真的过分思考了这一点 - 这里也有一些想法。


SELECT @BilledToDate = CONVERT(money, CASE WHEN SUM(ISNULL(invoiceamt,0)) > 0 THEN SUM(ISNULL(InvoiceAmt,0)) ELSE 0 END)

相同
SELECT @BilledToDate = CONVERT(money, SUM(ISNULL(invoiceamt,0)))

*注意在两者中使用ISNULL() - 这很重要,因为你无法对空值进行数学运算。


无需使用游标。只需在一个更新语句中将两个表连接在一起,然后批量处理它。

UPDATE StructuralOpenBilling
SET S.BilledToDate = I.BilledToDate
FROM
      StructuralOpenBilling S
   INNER JOIN
      (SELECT shortchar01, CONVERT(money, SUM(ISNULL(invoiceamt,0))) as BilledToDate
        FROM mfgsys803.dbo.invchead) I
   ON
      S.JobID = I.shortchar01

答案 1 :(得分:0)

这是否符合您的要求?

WITH inv AS
(
SELECT shortchar01, 
CONVERT(MONEY, CASE WHEN SUM(invoiceamt) > 0 THEN 
                                             SUM(InvoiceAmt) 
                                             ELSE 0 END) AS BilledToDate
FROM mfgsys803.dbo.invchead
GROUP BY shortchar01
)
 UPDATE StructuralOpenBilling
 SET BilledToDate = inv.BilledToDate, 
     BilledCheck = CONVERT(VARCHAR(50), inv.BilledToDate)
FROM StructuralOpenBilling sob
JOIN inv ON inv.shortchar01 = RTRIM(sob.JobID)