如何在 sql 服务器中解决此查询?

How can I solve this query in sql server?

Sql Fiddle example

我有这个 table 结构:

    CREATE TABLE IF NOT EXISTS `client` (
  `id` int(6) unsigned NOT NULL,
  `name` varchar(200),
  `balance` decimal NOT NULL,
  PRIMARY KEY (`id`)
) DEFAULT CHARSET=utf8;
INSERT INTO `client` (`id`, `name`, `balance`) VALUES
  ('1', 'Pepito', '500');


CREATE TABLE IF NOT EXISTS `balance_Movements` (
  `id` int(6) unsigned NOT NULL,
  `clientId` int(6),
  `movementType` varchar(200),
  `import` decimal NOT NULL,
  `dateMovement` datetime,
  PRIMARY KEY (`id`)
) DEFAULT CHARSET=utf8;
INSERT INTO `balance_Movements` (`id`, `clientid`, `movementType`, `import`, `dateMovement`) VALUES
  ('1', '1', 'payment', '50', '2018/05/11'),
  ('2', '1', 'refund', '25.05', '2018/05/10'),
  ('3', '1', 'refund', '60', '2018/04/06'),
  ('4', '1', 'payment', '100', '2018/04/03');

客户开始时有:500€ --> 所以声明变量将是这样的:

declare @total_balance as decimal;
set @total_balance = (select balance from client where id = 1);

Result
------
500

我需要在@total_balance的结果后进行更改,取最后一行的值:

示例:

Table_balance_Movements
------------------------

    Total
    -----
    450
    475.05
    535.05
    435.05

解释:

450 -->客户端是500开头的,所以如果movement类型是payment我需要把client的balance减去import movement,保存数据在 @total_balance 中,稍后使用 = 500 - 50 = 450

475.05 --> 我得到了 @total_balance 的值和 25.05 的总和,因为在这一行中,移动类型是 refund = 450 + 25.05 = 475.05

535.05 --> 同样的事情,我从 @total_balance 变量中获取值并查看移动的类型并减去或求和 import = 475.05 + 60 = 535.05

435.05 --> 535.05 - 100 = 435.05

我想做类似这个概念的东西:

  declare @total_balance as decimal;
set @total_balance = (select balance from client where id = 1);

select (case when movementType = 'payment' then (@total_balance = @total_balance - import) 
             when movementType = 'refund' then (@total_balance = @total_balance + import)  end) as total 
from balance_Movements;

有可能吗?谢谢

您可以使用累加和 window 函数解决此问题。以下将在 SQL 服务器和 MySQL 8+

中工作
select c.*,
       (c.balance +
        sum(case when bm.movement_type = 'payment' then - import
                 when bm.movement_type = 'refund' then import
            end) over (partition by c.id order by bm.datemovement)
       ) as net_balance
from client c join
     balance_movements bm
     on bm.clientid = c.id

您可以像这样只加上退款总额并减去付款总额:

SELECT 500 +
(SELECT SUM(import) FROM balance_Movements WHERE movementType = 'refund')
- (SELECT SUM(import) FROM balance_Movements WHERE movementType = 'payment') AS total

结果:435.05

我认为最简单的方法是使用 SUM 和条件聚合函数 window 函数来累加 balance

SELECT c.balance +SUM(CASE WHEN movementType = 'payment' THEN - import
                           WHEN movementType = 'refund' THEN  import
                      ELSE 0 END
            ) OVER(ORDER BY b.id)   Total
FROM client c 
JOIN balance_Movements b on c.id = b.clientid

但是如果你的dbms不支持window函数,你可以尝试在select

中正确使用子查询
SELECT c.balance + 
(
    SELECT SUM(CASE WHEN movementType = 'payment' THEN - import
                            WHEN movementType = 'refund' THEN  import
                          ELSE 0 END)
    FROM balance_Movements bb
    WHERE bb.id <= b.id and b.clientid = bb.clientid
)  Total
FROM client c 
JOIN balance_Movements b on c.id = b.clientid

sqlfiddle

试一试...

IF OBJECT_ID('tempdb..#balance_Movements', 'U') IS NOT NULL 
BEGIN DROP TABLE #balance_Movements; END;

CREATE TABLE #balance_Movements (
    id INT NOT NULL,
    clientId INT,
    movementType VARCHAR (200),
    import DECIMAL (9, 2) NOT NULL,
    dateMovement DATETIME,
    PRIMARY KEY (id)
);
INSERT INTO #balance_Movements (id, clientid, movementType, import, dateMovement) VALUES
  ('1', '1', 'payment', '50', '2018/05/11'),
  ('2', '1', 'refund', '25.05', '2018/05/10'),
  ('3', '1', 'refund', '60', '2018/04/06'),
  ('4', '1', 'payment', '100', '2018/04/03');

--=============================================================

DECLARE @_start DECIMAL(9,2) = 500;

SELECT 
    *,
    running_total = @_start - SUM(CASE WHEN bm.movementType = 'refund' THEN -1 * bm.import ELSE bm.import END) OVER (PARTITION BY bm.clientId ORDER BY bm.dateMovement desc)
FROM
    #balance_Movements bm;

结果...

id          clientId    movementType import     dateMovement            running_total
----------- ----------- ------------ ---------- ----------------------- --------------
1           1           payment      50.00      2018-05-11 00:00:00.000 450.00
2           1           refund       25.05      2018-05-10 00:00:00.000 475.05
3           1           refund       60.00      2018-04-06 00:00:00.000 535.05
4           1           payment      100.00     2018-04-03 00:00:00.000 435.05