如何在不使用循环时基于多个子表记录正确更新父表

时间:2016-03-16 20:35:20

标签: sql sql-server tsql

如何在不使用循环时根据多个子表记录正确更新父表?

下面的解决方案使用两个临时表并使用循环来回馈正确的平衡。

#customer-balance是主表,而#CUSTOMER_DEBIT_ENTRIES是包含多个条目的表。

还有其他方法吗?

IF OBJECT_ID ('tempdb.dbo.#CUSTOMER_BALANCE') IS NOT NULL 
    DROP TABLE #CUSTOMER_BALANCE
IF OBJECT_ID ('tempdb.dbo.#CUSTOMER_DEBIT_ENTRIES') IS NOT NULL 
    DROP TABLE #CUSTOMER_DEBIT_ENTRIES  


create table #CUSTOMER_BALANCE 
([RECNUM] decimal(8,0) IDENTITY(1,1) NOT NULL,
[CUSTOMER_ID][nchar](8) NOT NULL,
[CUST_BALANCE] [decimal] (14,4) DEFAULT((0))
PRIMARY KEY CLUSTERED(RECNUM)
);
INSERT INTO #CUSTOMER_BALANCE 
SELECT 'NGR',1500
UNION
SELECT 'ZGR',100
UNION
SELECT 'MKR',1000
UNION
SELECT 'DKR',1500
GO
SELECT * FROM #CUSTOMER_BALANCE



;create table #CUSTOMER_DEBIT_ENTRIES
([RECNUM] decimal(8,0) IDENTITY(1,1) NOT NULL,
[CUSTOMER_ID][nchar](8) NOT NULL,
[DEBIT_ENTRY] [decimal] (14,4) DEFAULT((0)),
[PROCESS_FLG] bit default 0,
PRIMARY KEY CLUSTERED(RECNUM)
);
INSERT INTO #CUSTOMER_DEBIT_ENTRIES 
SELECT 'NGR',500,0
UNION
SELECT 'ZGR',10,0
UNION
SELECT 'MKR',100,0
UNION
SELECT 'DKR',500,0
UNION
SELECT 'NGR',200,0
UNION
SELECT 'ZGR',20,0
Go

SELECT RECNUM,'#CUSTOMER_BALANCE'  AS TABLE_NAME,CUSTOMER_ID,CUST_BALANCE FROM #CUSTOMER_BALANCE 
SELECT RECNUM,'#CUSTOMER_DEBIT_ENTRIES'  AS TABLE_NAME,CUSTOMER_ID,DEBIT_ENTRY,PROCESS_FLG FROM #CUSTOMER_DEBIT_ENTRIES 

-- WRONG RESULT BELOW
Update #CUSTOMER_BALANCE
SET CUST_BALANCE = c.CUST_BALANCE - d.DEBIT_ENTRY
FROM #CUSTOMER_BALANCE c inner join #CUSTOMER_DEBIT_ENTRIES d
on c.CUSTOMER_ID = d.CUSTOMER_ID


--CORRECT RESULTS BELOW USING WHILE LOOPS

DECLARE @counter INT, @counter1 INT, @RECNUM INT
SET @counter = 0
SET @RECNUM = 0
SET @counter1 = (SELECT COUNT(*) FROM #CUSTOMER_DEBIT_ENTRIES WHERE PROCESS_FLG = 0)
WHILE @counter < @counter1
BEGIN
SET @RECNUM = (Select Top 1 RECNUM FROM #CUSTOMER_DEBIT_ENTRIES where PROCESS_FLG = 0)
UPDATE #CUSTOMER_BALANCE
SET CUST_BALANCE = c.CUST_BALANCE - d.DEBIT_ENTRY
FROM #CUSTOMER_BALANCE c inner join (SELECT TOP 1 RECNUM, CUSTOMER_ID,DEBIT_ENTRY,PROCESS_FLG FROM #CUSTOMER_DEBIT_ENTRIES 
WHERE RECNUM = @RECNUM AND PROCESS_FLG = 0) d on c.CUSTOMER_ID = d.CUSTOMER_ID

UPDATE #CUSTOMER_DEBIT_ENTRIES
SET PROCESS_FLG = 1 WHERE RECNUM = @RECNUM
set @counter  = @counter + 1
END

2 个答案:

答案 0 :(得分:0)

在使用聚合的情况下,您需要将每个PK值的行数减少为1:

Update #CUSTOMER_BALANCE
SET CUST_BALANCE = c.CUST_BALANCE - d.DEBIT_ENTRY
FROM #CUSTOMER_BALANCE c 
inner join
 ( select CUSTOMER_ID, sum(DEBIT_ENTRY) as DEBIT_ENTRY 
   from #CUSTOMER_DEBIT_ENTRIES
   GROUP BY CUSTOMER_ID
 ) as d
on c.CUSTOMER_ID = d.CUSTOMER_ID

答案 1 :(得分:-1)

这可以使用CTE实现:

;WITH CTE AS  
( SELECT customer_id, SUM(debit_entry) AS debit_entry  
FROM #CUSTOMER_DEBIT_ENTRIES  
GROUP BY CUSTOMER_ID  
)  

UPDATE #CUSTOMER_BALANCE  
SET CUST_BALANCE = CB.CUST_BALANCE - cte.DEBIT_ENTRY  
FROM CTE INNER JOIN #CUSTOMER_BALANCE CB   
ON CB.CUSTOMER_ID = CTE.CUSTOMER_ID