postgresql 存储过程 批量插入(根据插入的值 动态判断需要插入的字段) 以及 批量更改(根据更改的值 动态判断需要更改的字段)

发布于:2024-04-23 ⋅ 阅读:(26) ⋅ 点赞:(0)

postgresql 存储过程
循环插入 根据插入的值判断插入相应的字段

在PostgreSQL中,您可以使用PL/pgSQL语言编写函数,该函数可以在循环中执行插入操作,并根据插入的值判断应该插入哪些字段。但是,请注意,PostgreSQL通常不支持动态字段插入,因为表的结构是固定的。您通常需要在插入时提供所有字段的值,即使某些字段是NULL。

不过,您可以通过逻辑判断来确保只插入非NULL或符合特定条件的值。以下是一个示例函数,它使用循环来插入数据,并根据条件判断哪些字段应该被包含在INSERT语句中:

CREATE OR REPLACE FUNCTION loop_insert_based_on_value()  
RETURNS void AS 
$$
  
DECLARE  
    row_record RECORD; -- 用于存储从源表读取的行  
    should_insert_field1 BOOLEAN := false;  
    should_insert_field2 BOOLEAN := false;  
    should_insert_field3 BOOLEAN := false;  
BEGIN  
    -- 假设我们有一个源表source_data,从中读取数据  
    FOR row_record IN SELECT * FROM source_data LOOP  
        -- 根据row_record中的值判断哪些字段应该被插入  
        IF row_record.some_column IS NOT NULL AND row_record.some_column > 10 THEN  
            should_insert_field1 := true;  
        END IF;  
        IF row_record.another_column = 'value' THEN  
            should_insert_field2 := true;  
        END IF;  
        -- 添加更多条件判断...  
  
        -- 构建INSERT语句,只包含需要插入的字段  
        INSERT INTO target_table (  
            field1,  
            field2,  
            field3  
        ) VALUES (  
            CASE WHEN should_insert_field1 THEN row_record.value_for_field1 ELSE NULL END,  
            CASE WHEN should_insert_field2 THEN row_record.value_for_field2 ELSE NULL END,  
            CASE WHEN should_insert_field3 THEN row_record.value_for_field3 ELSE NULL END  
        );  
  
        -- 重置字段插入标志,为下一次循环做准备  
        should_insert_field1 := false;  
        should_insert_field2 := false;  
        should_insert_field3 := false;  
    END LOOP;  
END;  

$$
 LANGUAGE plpgsql;

在这个函数中,我们首先声明了一些变量来跟踪哪些字段应该被插入。然后,我们使用一个FOR循环来遍历源表source_data中的每一行。对于每一行,我们检查某些条件,并设置相应的标志变量。最后,我们构建一个INSERT语句,只包括那些其标志变量为TRUE的字段。我们使用CASE语句在INSERT中为这些字段提供值,或者如果不需要插入该字段,则提供NULL。

请注意,这个示例假设source_data表中包含用于决定哪些字段应该被插入的列(如some_column和another_column),以及用于插入到target_table中的实际值(如value_for_field1,value_for_field2和value_for_field3)。您需要根据您的实际表结构和业务需求来调整这些列名。

此外,虽然这种方法可以实现基于值的字段插入,但它并不是最优的,因为它在每次循环迭代时都执行一个完整的INSERT语句。如果可能,最好优化您的数据库模式或业务逻辑,以避免这种动态字段插入的需求。

实战sql,批量新增

CREATE OR REPLACE PROCEDURE public.data_read_zao0070(p_org_id integer, p_uid character varying, p_user_id character varying)
 LANGUAGE plpgsql
AS $procedure$
DECLARE
  p_result_count integer;
  current_row RECORD;  
  current_row2 RECORD;  
  current_rows varchar[];
  current_value varchar;
 
 -- 定义判断需要增加的字段,为true需要增加,false不需要增加。
inventory_used_field1 BOOLEAN := false;  
inventory_used_amount_field2 BOOLEAN := false;  
inventory_nonused_field3 BOOLEAN := false;  
inventory_nonused_amount_field4 BOOLEAN := false;  


	-- 循环插入				
			FOR current_row2 IN  (select
					m.* 
					from
						plant_if_sap_zao0070 m
					where
						not exists (
							select
								*
							from
								plant_actual p
							where
								m.del_flag = '0'
								and p.del_flag = '0'
								and trim(m.m_code) = trim(p.m_code)
								and 
								to_char((date_trunc('MONTH', to_date(m.stock_years, 'YYYYMM') + interval '1 month') - interval '1 day')::date, 'YYYY-MM-DD')   
								= p.plt_shp_dt
								and 
								to_char((date_trunc('MONTH', to_date(m.stock_years, 'YYYYMM') + interval '1 month') - interval '1 day')::date, 'YYYY-MM-DD')   
								= p.shipping_dt)
						and exists (
							select
								*
							from
								plant_m_model mo
							where
								mo.del_flag = '0'
								and m.del_flag = '0'
								and trim(mo.m_code) = trim(m.m_code))
								and m.org_id = p_org_id) LOOP				

				IF trim(current_row2.warehouse_code) = 'BLK' THEN  
		           inventory_nonused_field3 := true;  
		           inventory_nonused_amount_field4 := true;  
		        END IF; 
		       	IF trim(current_row2.warehouse_code) = 'URG' THEN  
		           inventory_used_field1  := true;  
		           inventory_used_amount_field2  := true;  
		        END IF; 

		        raise notice '++++++++++ ';
		        raise notice '标记: [%] ',inventory_nonused_field3;
		        raise notice '标记: [%] ',inventory_nonused_amount_field4;
		        raise notice '标记: [%] ',inventory_used_field1;
		        raise notice '标记: [%] ',inventory_used_amount_field2;
		        raise notice '++++++++++ ';

		       INSERT INTO public.plant_actual
				(	
				org_id, m_code, bo_code, plt_shp_dt, shipping_dt, currency, 
				inventory_used, inventory_used_amount, inventory_nonused, inventory_nonused_amount,
				create_by, modify_by
				)values(
			        p_org_id,
					trim(current_row2.m_code),
					null,
				    to_char((date_trunc('MONTH', to_date(current_row2.stock_years, 'YYYYMM') + interval '1 month') - interval '1 day')::date, 'YYYY-MM-DD'),
				    to_char((date_trunc('MONTH', to_date(current_row2.stock_years, 'YYYYMM') + interval '1 month') - interval '1 day')::date, 'YYYY-MM-DD'),
				    'CNY',
				    CASE WHEN inventory_used_field1 THEN CAST(CONCAT(current_row2.q_qty_sign,current_row2.q_qty_number) AS NUMERIC)  ELSE NULL END,  
				    CASE WHEN inventory_used_amount_field2 THEN  CAST(CONCAT(current_row2.q_amount_sign,current_row2.q_amount_number, '.', current_row2.q_amount_point) AS NUMERIC) ELSE NULL END,  
				    CASE WHEN inventory_nonused_field3 THEN  CAST(CONCAT(current_row2.r_qty_sign,current_row2.r_qty_number) AS NUMERIC) ELSE NULL END,  
				    CASE WHEN inventory_nonused_amount_field4 THEN CAST(CONCAT(current_row2.r_amount_sign,current_row2.r_amount_number, '.', current_row2.r_amount_point) AS NUMERIC) ELSE NULL END,  
					p_user_id,
					p_user_id 
			);		
		
		-- 循环结束 重置变量
		        inventory_used_field1 := false;  
		        inventory_used_amount_field2 := false;  
			    inventory_nonused_field3 := false;  
				inventory_nonused_amount_field4 := false;  				
			END LOOP;  

实战sql,批量更新 具体逻辑 思路仿照上面新增的思路

CREATE OR REPLACE PROCEDURE public.data_read_zao0070(p_org_id integer, p_uid character varying, p_user_id character varying)
 LANGUAGE plpgsql
AS $procedure$
DECLARE
  p_result_count integer;
  current_row RECORD;  
  current_row2 RECORD;  
  current_rows varchar[];
  current_value varchar;
 
inventory_used_field1 BOOLEAN := false;  
inventory_used_amount_field2 BOOLEAN := false;  
inventory_nonused_field3 BOOLEAN := false;  
inventory_nonused_amount_field4 BOOLEAN := false;  

 	FOR current_row IN  (
				  select 
						m.* 
						from
							plant_if_sap_zao0070 m
						where
					 		exists (
								select
									*
								from
									plant_actual p
								where
									m.del_flag = '0'
									and p.del_flag = '0'
									and trim(m.m_code) = trim(p.m_code)
									and p.plt_shp_dt =  
									to_char((date_trunc('MONTH', to_date(m.stock_years, 'YYYYMM') + interval '1 month') - interval '1 day')::date, 'YYYY-MM-DD')   
									and p.shipping_dt = 
									to_char((date_trunc('MONTH', to_date(m.stock_years, 'YYYYMM') + interval '1 month') - interval '1 day')::date, 'YYYY-MM-DD')   
								)
							and exists (
								select
									*
								from
									plant_m_model mo
								where
									mo.del_flag = '0'
									and m.del_flag = '0'
									and trim(mo.m_code) = trim(m.m_code))
									and m.org_id = p_org_id				
						) LOOP 
						
				 raise notice '更改数据 : [%] ',current_row;						
						
				IF trim(current_row.warehouse_code) = 'BLK' THEN  
		           inventory_nonused_field3 := true;  
		           inventory_nonused_amount_field4 := true;  
		        END IF; 
		       	IF trim(current_row.warehouse_code) = 'URG' THEN  
		           inventory_used_field1  := true;  
		           inventory_used_amount_field2  := true;  
		        END IF; 
								
		        raise notice '--------- ';
		        raise notice '标记: [%] ',inventory_nonused_field3;
		        raise notice '标记: [%] ',inventory_nonused_amount_field4;
		        raise notice '标记: [%] ',inventory_used_field1;
		        raise notice '标记: [%] ',inventory_used_amount_field2;
		        raise notice '--------- ';
				
		    UPDATE public.plant_actual
				SET 
				inventory_used=
				CASE WHEN inventory_used_field1 THEN 
				CAST(CONCAT(current_row.q_qty_sign,current_row.q_qty_number) AS NUMERIC)  ELSE NULL END,  
				inventory_used_amount=
				CASE WHEN inventory_used_amount_field2 THEN  CAST(CONCAT(current_row.q_amount_sign,current_row.q_amount_number, '.', current_row.q_amount_point) AS NUMERIC) ELSE NULL END,  
				inventory_nonused=
				CASE WHEN inventory_nonused_field3 THEN  CAST(CONCAT(current_row.r_qty_sign,current_row.r_qty_number) AS NUMERIC) ELSE NULL END,  
				inventory_nonused_amount=
				CASE WHEN inventory_nonused_amount_field4 THEN CAST(CONCAT(current_row.r_amount_sign,current_row.r_amount_number, '.', current_row.r_amount_point) AS NUMERIC) ELSE NULL END,  
				modify_by=p_user_id
				WHERE trim(m_code)=trim(current_row.m_code) 
				AND plt_shp_dt = 
				to_char((date_trunc('MONTH', to_date(current_row.stock_years, 'YYYYMM') + interval '1 month') - interval '1 day')::date, 'YYYY-MM-DD')   
				and shipping_dt = 
				to_char((date_trunc('MONTH', to_date(current_row.stock_years, 'YYYYMM') + interval '1 month') - interval '1 day')::date, 'YYYY-MM-DD')   	
			    and del_flag='0' and  org_id=p_org_id;	
			
			-- 增加一步修改状态为1
			update plant_if_sap_zao0070 set del_flag = '1'
			where trim(m_code) = trim(current_row.m_code) and org_id = p_org_id;

	  		inventory_used_field1 := false;  
	        inventory_used_amount_field2 := false;  
		    inventory_nonused_field3 := false;  
			inventory_nonused_amount_field4 := false;  	
		
 END LOOP;