PostgreSQL: Iterate through a tables rows with for loop, retrieve column value based on current row

点点圈 提交于 2019-12-24 07:09:30

问题


I have the following 2 tables

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);

I have the following pseudo code:

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; $$

It's purpose is count how many rows in the table (salesperson) have the 'territoryid' of the the currentRows->'territory2.territoryid', and then assign that quantity to currentRows->territory2.total_sales_person.


回答1:


You don't need a loop or even a function for this.

What you want to do can be done in a single update statement because the total count per territory can be calculated with a single aggregation:

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

This can then be used as the source to update the territory table:

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;

An alternative that might be easier to understand but will be slower for larger tables is an update with a co-related sub-query

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

There is a slight difference between the first and second update: the second one will update the total_sales_person to 0 (zero) for those territories where there is no salesperson at all. The first one will only update the count for territories that are actually present in the salesperson table.


Unrelated, but: having a "type identifying" prefix or suffix for an identifier is usually useless and doesn't really help at all. See a related discussion on dba.stackexchange



来源:https://stackoverflow.com/questions/40831736/postgresql-iterate-through-a-tables-rows-with-for-loop-retrieve-column-value-b

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!