如何从先前行的字段值中减去插入的值,以便在语句中的每个条目中执行。

huangapple go评论65阅读模式
英文:

How to subtract inserted value from previous rows field value for each entry in a statement

问题

我需要在当天的每个发货中进行插入操作。我遇到了从前一行扣除总金额的问题。我正在插入到表C中,但是如果我一天中有多个订单,它只会获取最后一次借记条目并从最初的最后一行总额中扣除。我知道这是因为我在使用ORDER BY DESC LIMIT 1,但我想不出另一种获取最后一行总额列值的方法。我还需要第二次插入从上一次插入获取新的总额。

我在我的插入语句中使用一个变量内的选择语句。@vTotal

如果只有一个条目插入,那么它将起作用,但是如果选择语句中有多行,我该如何让它起作用,或者是否有更好的方法?

以下是我的当前测试查询:

SET @vCreatedbt := 'name@domain.com';
SET @vTotal := (SELECT tableC.total - tableB.ShipmentCharge AS total 
                FROM tableC, tableB 
                ORDER BY id DESC 
                LIMIT 1);
SET @vwork_order_id := null;
SET @vModified := null;
SET @vModified_by := null;
SET @vCredit := null;
SET @vid := null;

INSERT INTO tableC
    SELECT @vId AS id, client_name AS descr, @vWork_order_id AS work_order_id, 
            @vCredit AS credit, ShipmentCharge as debit, @vTotal AS total, 
            now() as created, @vCreatedby as createdby, 
            @vModified AS modified, @vModified_by AS modified_by
    FROM tblA
        INNER JOIN tableD ON tableA.id = tableD.id
        INNER JOIN tableB ON tableD.tracking_number = tableB.TrackingNumber
        WHERE tableA.status = 'Order Shipped';

只显示表C的这三个字段以简化

id debit total
1 27.37 15260.96

查询结果如下

id debit total
1 27.37 15260.96
2 25.96 15235.96
3 25.00 15235.96

id是自动递增的。

英文:

I need to do an insert into a table of each shipment that day. I am having a problem deducting the total amount from the previous row. I am inserting into tableC, but since if I have multiple orders in a day its only grabbing the last debit entry and deducting from the original last rows total. I know this is because I am using the ORDER BY DESC LIMIT 1, but I can't think of another way to get the last rows total column value. I also need the second insertion to get the new total from the previous insertion.

I am using a select statement inside a variable to run inside my insert statment. @vTotal

If its a single entry insertion it would work, but how do I this to work if there is multiple rows in the select statement, or is there a better way to do this?

Below is my current test query:

SET @vCreatedbt := 'name@domain.com';
SET @vTotal := (SELECT tableC.total - tableB.ShipmentCharge AS total 
                FROM tableC, tableB 
                ORDER BY id DESC 
                LIMIT 1);
SET @vwork_order_id := null;
SET @vModified := null;
SET @vModified_by := null;
SET @vCredit := null;
SET @vid := null;

INSERT INTO tableC
    SELECT @vId AS id, client_name AS descr, @vWork_order_id AS work_order_id, 
            @vCredit AS credit, ShipmentCharge as debit, @vTotal AS total, 
            now() as created, @vCreatedby as createdby, 
            @vModified AS modified, @vModified_by AS modified_by
    FROM tblA
        INNER JOIN tableD ON tableA.id = tableD.id
        INNER JOIN tableB ON tableD.tracking_number = tableB.TrackingNumber
        WHERE tableA.status = 'Order Shipped'

Just showing these three fields of tableC to simplify

id debit total
1 27.37 15260.96

Query is giving me

id debit total
1 27.37 15260.96
2 25.96 15235.96
3 25.00 15235.96

The id is auto incremented

答案1

得分: 1

创建表格 balance:
---
```sql
CREATE TABLE balance (
  id INT AUTO_INCREMENT PRIMARY KEY,
  person_id INT NOT NULL,
  action DECIMAL(10, 2) NOT NULL,
  balance DECIMAL(10, 2) NOT NULL DEFAULT 0,
  created_at DATETIME(6) NOT NULL DEFAULT CURRENT_TIMESTAMP(6),
  CONSTRAINT balance_cannot_be_negative CHECK (balance >= 0)
);

创建触发器 set_balance:

CREATE TRIGGER set_balance
BEFORE INSERT ON balance
FOR EACH ROW
  SET NEW.balance = COALESCE(
    (
    SELECT balance 
    FROM balance
    WHERE person_id = NEW.person_id
    ORDER BY created_at DESC LIMIT 1
    ), 0) + NEW.action;

插入数据到 balance 表格:

INSERT INTO balance (person_id, action) VALUES (1, 100); -- 添加 $100,余额 $100
INSERT INTO balance (person_id, action) VALUES (1, -20); -- 消费 $20,余额 $80
INSERT INTO balance (person_id, action) VALUES (2, 50);  -- 添加 $50,余额 $50
INSERT INTO balance (person_id, action) VALUES (1, 10);  -- 添加 $10,余额 $90
INSERT INTO balance (person_id, action) VALUES (2, 30);  -- 添加 $30,余额 $80
INSERT INTO balance (person_id, action) VALUES (2, -40); -- 消费 $40,余额 $40

尝试消费 $100 超过当前余额,生成错误:

-- 尝试消费 $100,超过当前余额,生成错误
INSERT INTO balance (person_id, action) VALUES (2, -100); 

> error > 违反了检查约束 'balance_cannot_be_negative'。 >

从 balance 表格中选择数据,按 id 或 person_id 和创建时间排序:

SELECT * FROM balance ORDER BY id;
SELECT * FROM balance ORDER BY person_id, created_at;

按 id 排序的结果:

id person_id action balance created_at
1 1 100.00 100.00 2023-06-08 18:05:59.811375
2 1 -20.00 80.00 2023-06-08 18:05:59.817546
3 2 50.00 50.00 2023-06-08 18:05:59.819130
4 1 10.00 90.00 2023-06-08 18:05:59.820016
5 2 30.00 80.00 2023-06-08 18:05:59.821140
6 2 -40.00 40.00 2023-06-08 18:05:59.822273

按 person_id 和创建时间 排序的结果:

id person_id action balance created_at
1 1 100.00 100.00 2023-06-08 18:05:59.811375
2 1 -20.00 80.00 2023-06-08 18:05:59.817546
4 1 10.00 90.00 2023-06-08 18:05:59.820016
3 2 50.00 50.00 2023-06-08 18:05:59.819130
5 2 30.00 80.00 2023-06-08 18:05:59.821140
6 2 -40.00 40.00 2023-06-08 18:05:59.822273

[fiddle](https://dbfiddle.uk/Xa0qVufr)

在示例中,需要使用 `DATETIME(6)`,因为普通的 `DATETIME` 不提供所需的精度。在实际应用中,`DATETIME` 应该足够用了 - 我怀疑一个人在一秒内执行两笔不同的交易... 或者你可以使用 `id` 而不是 `created_at` 来对行进行排序。
英文:

DEMO:

CREATE TABLE balance (
  id INT AUTO_INCREMENT PRIMARY KEY,
  person_id INT NOT NULL,
  action DECIMAL(10, 2) NOT NULL,
  balance DECIMAL(10, 2) NOT NULL DEFAULT 0,
  created_at DATETIME(6) NOT NULL DEFAULT CURRENT_TIMESTAMP(6),
  CONSTRAINT balance_cannot_be_negative CHECK (balance >= 0)
);
CREATE TRIGGER set_balance
BEFORE INSERT ON balance
FOR EACH ROW
  SET NEW.balance = COALESCE(
    (
    SELECT balance 
    FROM balance
    WHERE person_id = NEW.person_id
    ORDER BY created_at DESC LIMIT 1
    ), 0) + NEW.action;
INSERT INTO balance (person_id, action) VALUES (1, 100); -- add $100, balance $100
INSERT INTO balance (person_id, action) VALUES (1, -20); -- spend $20, balance $80
INSERT INTO balance (person_id, action) VALUES (2, 50);  -- add $50, balance $50
INSERT INTO balance (person_id, action) VALUES (1, 10);  -- add $10, balance $90
INSERT INTO balance (person_id, action) VALUES (2, 30);  -- add $30, balance $80
INSERT INTO balance (person_id, action) VALUES (2, -40); -- spend $40, balance $40
-- try to spend $100 which is over current balance, error generated
INSERT INTO balance (person_id, action) VALUES (2, -100); 

> error
> Check constraint 'balance_cannot_be_negative' is violated.
>

SELECT * FROM balance ORDER BY id;
SELECT * FROM balance ORDER BY person_id, created_at;
id person_id action balance created_at
1 1 100.00 100.00 2023-06-08 18:05:59.811375
2 1 -20.00 80.00 2023-06-08 18:05:59.817546
3 2 50.00 50.00 2023-06-08 18:05:59.819130
4 1 10.00 90.00 2023-06-08 18:05:59.820016
5 2 30.00 80.00 2023-06-08 18:05:59.821140
6 2 -40.00 40.00 2023-06-08 18:05:59.822273
id person_id action balance created_at
1 1 100.00 100.00 2023-06-08 18:05:59.811375
2 1 -20.00 80.00 2023-06-08 18:05:59.817546
4 1 10.00 90.00 2023-06-08 18:05:59.820016
3 2 50.00 50.00 2023-06-08 18:05:59.819130
5 2 30.00 80.00 2023-06-08 18:05:59.821140
6 2 -40.00 40.00 2023-06-08 18:05:59.822273

fiddle

DATETIME(6) needed in the fiddle - common DATETIME does not provide needed accuracy. In practice DATETIME must be enough - I doubt that the person can perform two separate transactoins within a second.. or you may use not created_at but id for rows ordering.

huangapple
  • 本文由 发表于 2023年6月9日 01:15:56
  • 转载请务必保留本文链接:https://go.coder-hub.com/76434255.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定