2016-03-16 2 views
0

Как правильно обновлять родительскую таблицу на основе нескольких записей дочерних таблиц при отсутствии циклов?Как правильно обновлять родительскую таблицу на основе нескольких записей дочерних таблиц при отсутствии циклов

В приведенном ниже решении используются две таблицы temp и используются циклы, чтобы вернуть правильный баланс.

#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 

ответ

0

Вам необходимо сократить количество строк на PK-значение к единице, в вашем случае, используя агрегацию:

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

Это может быть достигнуто с помощью КТР:

;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 
Смежные вопросы