我在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
任何想法都会受到赞赏。
感谢。
约翰
答案 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)