Sql 根据以前的行更新存储的记录编号

Sql 根据以前的行更新存储的记录编号,sql,postgresql,Sql,Postgresql,我必须创建脚本,根据以下条件设置数据库中一个表的列: 每个销售订单(表销售订单)在销售订单人员(表销售订单人员)中都有记录,其中存储了人员的电子邮件 我必须按订单时间ASC订购销售订单中的所有记录(因此最早的订单将排在第一位),并且在这些订单上,我必须设置销售订单名称排名列(即该列表示客户的订单数量。它基于销售订单人员中的电子邮件)。因此,客户的第一个订单将有1个,第二个订单将有2个,等等。这必须为一个客户完成 所有这些逻辑都将存储在liquibase中(因此它只运行一次,接下来的记录将由Ja

我必须创建脚本,根据以下条件设置数据库中一个表的列:

  • 每个销售订单(表销售订单)在销售订单人员(表销售订单人员)中都有记录,其中存储了人员的电子邮件

  • 我必须按订单时间ASC订购销售订单中的所有记录(因此最早的订单将排在第一位),并且在这些订单上,我必须设置销售订单名称排名列(即该列表示客户的订单数量。它基于销售订单人员中的电子邮件)。因此,客户的第一个订单将有1个,第二个订单将有2个,等等。这必须为一个客户完成

  • 所有这些逻辑都将存储在liquibase中(因此它只运行一次,接下来的记录将由Java在行创建时进行管理。但是旧数据必须首先通过liquibase进行管理)
我已经写了这个程序。但它不起作用,它只是将数字1设置为表的一半(可能是因为它的测试表,所以可能存在销售订单的人没有邮件或记录的情况)。 有人能帮我吗?这是我的第一个SQL过程,所以我不知道出了什么问题

CREATE OR REPLACE FUNCTION updateSellingOrderCustomerCount()
    RETURNS VOID AS
$$
DECLARE
    t_curs CURSOR FOR SELECT so.*, sop.email
                      FROM selling_order so
                               INNER JOIN selling_order_person sop on so.person_id = sop.id
                      ORDER BY order_time;
BEGIN
    FOR tmp IN t_curs
        LOOP
            UPDATE selling_order
            SET rank =
                    (SELECT COALESCE(MAX(so.rank), 1)
                     FROM selling_order so
                              INNER JOIN selling_order_person sop on so.person_id = sop.id
                     WHERE sop.email = tmp.email)
            WHERE selling_order.id = tmp.id;
        END LOOP;
END
$$ LANGUAGE plpgsql VOLATILE;

SELECT * FROM updateSellingOrderCustomerCount();
为了简单起见,我删除了所有我们现在无法使用的栏目。

create table selling_order
(
    id bigserial not null
        constraint selling_order_pkey
            primary key,
    selling_order_person_id bigint not null,
    rank int,
    order_time timestamp
);

create index idx_selling_order_person_id
    on selling_order (person_id);


create table selling_order_person
(
    id bigserial not null
        constraint pk_selling_order_person
            primary key,
    email varchar(64)
);

据我所知,这可以通过一个UPDATE语句来完成

update selling_order so
  set rank = t.rnk
from (
  select id, 
         row_number() over (partition by selling_order_person_id order by order_time) as rnk
  from selling_order
) t
where t.id = so.id;
我假设您在“客户已经完成了多少订单”中提到的客户是指
销售订单\u人员\u id
而不是指某个隐藏的“客户”列

在线示例:



但是管理这个
rank
列似乎毫无用处,因为你可以很容易地计算出这些信息(如UPDATE语句的内部SELECT所示)

多亏了一个没有名字的马。我刚刚编辑了一点他的代码,效果很好

UPDATE selling_order so
    SET rank = tmp.rnk
    FROM (
             SELECT so.id, sop.email,
                    ROW_NUMBER() OVER (PARTITION BY LOWER(sop.email) ORDER BY order_time) AS rnk
             FROM selling_order so
                      INNER JOIN selling_order_person sop ON so.selling_order_person_id = sop.id
         ) tmp
    WHERE tmp.id = so.id;

改用触发器,以确保数据一致性。(或者只允许通过存储过程进行更新/插入/删除。)但我需要管理所有现有记录。因此,插入上的触发器不起作用。我只需要设置这些数据一次,然后它将以适当的值存储在新记录中。这就是Java在创建销售订单时所做的。请发布两个表和一些示例数据的模式(作为创建表…)。我很难理解问题顶部用文字描述模式的一大块文本——我宁愿用SQLAdded阅读。我跳过了我们不使用的专栏。“为了简单起见,我删除了我们现在不使用的所有专栏”-您还删除了回答此问题所必需的
rank
order\u time
专栏。我不知道定义排名顺序的列的确切位置。首先,不动态计算排名的决定是性能原因。通常会显示所有销售订单的列表。所以一遍又一遍的计算是没有用的。第二个事实是,当我使用您的SQL时,结果是rank列只包含1(即使对于使用同一电子邮件的人有多个订单),那么您要么没有运行如图所示的语句(因为这显然适用于您提供的信息:)或者你漏掉了一些重要的细节,但有一些误解。我对此做了一点修改,效果很好(我会在下面发布)。因为我不能参加销售订单,我需要通过电子邮件加入。它的订单没有注册,因此可以有5条具有唯一id但具有相同电子邮件的记录。当您可以从selling_order表本身通过selling_order_person_id进行分区时,您不必加入selling_order_person并通过电子邮件进行分区,就像它是由没有名称的_horse_完成的一样。您额外的连接只会增加查询执行时间。正如我所说的,有很多误解。一封电子邮件中的selling_order_person记录不是唯一的。在selling_order_person中可以有50行包含相同的电子邮件(对于每个客户未登录的订单,因此他每次都会自己输入凭据,这与selling_order是1:1)。因此,我无法加入销售订单人员id。因为这会导致所有订单都有排名1(所有id都是唯一的)