Além dos comentários e respostas que você já recebeu, acredito que você complicou demais seu procedimento. Você está fazendo as coisas de forma muito processual, em vez de pensar em conjuntos como deveria. Você também está obtendo as colunas agregadas em três consultas que são essencialmente idênticas (por exemplo, mesmas tabelas, condições de junção e predicados) - você pode combiná-las para obter os três resultados em uma única consulta.
Parece que você está tentando inserir na tabela clienthistoricalpurchases se uma linha ainda não existir para esse cliente, caso contrário, você atualiza a linha. Isso imediatamente grita "declaração MERGE" para mim.
Combinando tudo isso, acho que seu procedimento atual deve conter apenas uma única instrução de mesclagem:
MERGE INTO clienthistoricalpurchases tgt
USING (SELECT clients.client_id,
COUNT(DISTINCT od.productid) distinct_products,
COUNT(od.productid) total_products,
SUM((od.unitprice * od.quantity) - od.discount) proposed_new_balance
FROM orderdetails od
INNER JOIN orders
ON orderdetails.orderid = orders.orderid
INNER JOIN clients
ON orders.clientid = clients.clientid
GROUP BY clients.client_id) src
ON (tgt.clientid = src.client_id)
WHEN NOT MATCHED THEN
INSERT (tgt.clientid,
tgt.distinctproducts,
tgt.totalproducts,
tgt.totalcost)
VALUES (src.clientid,
src.distinct_products,
src.total_products,
src.proposed_new_balance)
WHEN MATCHED THEN
UPDATE SET tgt.distinctproducts = src.distinct_products,
tgt.totalproducts = src.total_products,
tgt.totalcost = src.proposed_new_balance;
No entanto, tenho algumas preocupações sobre sua lógica atual e/ou modelo de dados.
Parece que você espera que no máximo uma linha por clientid apareça em clienthistoricalpurchases. E se um clientid tiver dois ou mais pedidos diferentes? Atualmente, você substituiria qualquer linha existente.
Além disso, você realmente deseja aplicar essa lógica em todos os pedidos sempre que for executado?