【问题标题】:PostgreSQL: Iterate through a tables rows with for loop, retrieve column value based on current rowPostgreSQL:使用for循环遍历表行,根据当前行检索列值
【发布时间】:2023-11-25 13:29:01
【问题描述】:

我有以下 2 个表

CREATE TABLE salesperson_t (
    salespersonid numeric(4,0) NOT NULL,
    salespersonname character varying(25),
    salespersontelephone character varying(50),
    salespersonfax character varying(50),
    salespersonaddress character varying(30),
    salespersoncity character varying(20),
    salespersonstate character(2),
    salespersonzip character varying(20),
    salesterritoryid numeric(4,0),
    CONSTRAINT salesperson_pk PRIMARY KEY (salespersonid)
);

INSERT INTO salesperson_t VALUES (1, 'Doug Henny', '8134445555', NULL, NULL, NULL, NULL, NULL, 2);
INSERT INTO salesperson_t VALUES (2, 'Robert Lewis', '8139264006', NULL, '124 Deerfield', 'Lutz', 'FL', '33549', 13);
INSERT INTO salesperson_t VALUES (3, 'William Strong', '3153821212', NULL, '787 Syracuse Lane', 'Syracuse', 'NY', '33240', 3);
INSERT INTO salesperson_t VALUES (4, 'Julie Dawson', '4355346677', NULL, NULL, NULL, NULL, NULL, 4);
INSERT INTO salesperson_t VALUES (5, 'Jacob Winslow', '2238973498', NULL, NULL, NULL, NULL, NULL, 5);
INSERT INTO salesperson_t VALUES (6, 'Pepe Lepue', NULL, NULL, NULL, 'Platsburg', 'NY', NULL, 13);
INSERT INTO salesperson_t VALUES (8, 'Fred Flinstone', NULL, NULL, '1 Rock Lane', 'Bedrock', 'Ca', '99999', 2);
INSERT INTO salesperson_t VALUES (9, 'Mary James', '3035555454', NULL, '9 Red Line', 'Denver', 'CO', '55555', 4);
INSERT INTO salesperson_t VALUES (10, 'Mary Smithson', '4075555555', NULL, '4585 Maple Dr', 'Orlando', 'FL', '32826', 15);

CREATE TABLE territory2_t (
    territoryid numeric(4,0),
    territoryname character varying(50),
    total_sales_person integer,
    CONSTRAINT territory2_t_pk PRIMARY KEY (territoryid)
);

INSERT INTO territory2_t VALUES (1, 'SouthEast', NULL);
INSERT INTO territory2_t VALUES (2, 'SouthWest', NULL);
INSERT INTO territory2_t VALUES (3, 'NorthEast', NULL);
INSERT INTO territory2_t VALUES (4, 'NorthWest', NULL);
INSERT INTO territory2_t VALUES (5, 'Central', NULL);
INSERT INTO territory2_t VALUES (6, 'Alaska', NULL);
INSERT INTO territory2_t VALUES (12, 'Hawaii', NULL);
INSERT INTO territory2_t VALUES (13, 'Colorado', NULL);
INSERT INTO territory2_t VALUES (15, 'Arizona', NULL);

我有以下伪代码:

DO $$
DECLARE
    -- currentRow [relevant datatype];
BEGIN
    FOR counter IN 1..(SELECT count(*)FROM territory2_t) LOOP -- There are 13 total rows

        -- **assign currentRow to counter**

        RAISE NOTICE 'Counter: %', counter; -- debugging purposes

        UPDATE terriory2_t
        SET total_sales_person = ((SELECT count(*)
                                    FROM salesperson_t
                                    WHERE salesterritoryid = currentRow.territoryid)*1) -- *1 is for debuggin puporses
        WHERE territoryid = currentRow.territoryid;

        -- **increase currentRow by 1**
    END LOOP;
END; $$

它的目的是计算表中有多少行(销售人员)具有currentRows->'territory2.territoryid'的'territoryid',然后将该数量分配给currentRows->territory2.total_sales_person。

【问题讨论】:

    标签: postgresql loops for-loop rows


    【解决方案1】:

    您不需要循环甚至函数。

    您想要做的事情可以在单个更新语句中完成,因为可以使用单个聚合计算每个区域的总计数:

    SELECT salesterritoryid, count(*) as total_count
    FROM salesperson_t
    group by salesterritoryid
    

    然后可以将其用作更新区域表的源:

    UPDATE territory2_t
       SET total_sales_person = t.total_count
    FROM (
       SELECT salesterritoryid, count(*) as total_count
       FROM salesperson_t
       group by salesterritoryid
    ) t 
    WHERE territoryid = t.salesterritoryid;
    

    另一种可能更容易理解但对于较大的表会更慢的替代方法是使用共同相关的子查询进行更新

    UPDATE territory2_t tg
       SET total_sales_person = (select count(*) 
                                 from salesperson_t sp
                                 where sp.salesterritoryid = tg.territoryid);
    

    第一次和第二次更新之间存在细微差别:对于根本没有销售人员的地区,第二次更新会将 total_sales_person 更新为 0(零)。第一个只会更新 salesperson 表中实际存在的地区的计数。


    不相关,但是:为标识符添加“类型识别”前缀或后缀通常是无用的,而且根本没有真正的帮助。见a related discussion on dba.stackexchange

    【讨论】:

    • 谢谢。第一个解决方案还允许我将数据从表的一个列传输到另一个表的列。
    最近更新 更多