PostgreSQL的pl/pgSQL函数改造为Snowflake兼容版本技术咨询
Snowflake兼容版停车时长计算方案
由于当前Snowflake暂不支持PL/pgSQL语法,我们将原有函数改造为Snowflake原生SQL存储过程,完全匹配业务需求:
核心适配调整点
- 移除PostgreSQL特有
nextval语法:durations表已配置autoincrement自增主键,插入时无需显式指定id字段 - 时间语法适配:用Snowflake原生
DATEDIFF计算秒级时长,DATEADD做日期偏移计算 - 变量优化:提前读取properties配置值减少子查询嵌套,提升执行效率
- 所有原有业务校验规则完整保留:过滤XX前缀厂商、避免重复写入、动态更新截止日期逻辑完全不变
完整存储过程代码
CREATE OR REPLACE PROCEDURE calculateDuration() RETURNS VARCHAR LANGUAGE SQL AS $$ DECLARE v_limit_date TIMESTAMP; v_limit_days INT; v_max_event_time TIMESTAMP; BEGIN -- 读取配置参数 SELECT PROP_VALUE::TIMESTAMP INTO v_limit_date FROM properties WHERE prop_key = 'DURATION.LIMIT.DATE'; SELECT PROP_VALUE::INT INTO v_limit_days FROM properties WHERE prop_key = 'DURATION.LIMIT.DAYS'; -- 插入匹配的进出时长记录 INSERT INTO durations ( odb_created_at, event_id_arrival, event_id_departure, event_time_arrival, event_time_departure, card_nr, ticket_type, duration, manufacturer, carpark_id ) WITH cte AS ( SELECT e.id, e.card_nr, e.event_time, e.ticket_type, e.manufacturer, e.carpark_id, e.device_type, ROW_NUMBER() OVER (ORDER BY e.card_nr, e.carpark_id, e.event_time, e.device_type) AS rn FROM events e LEFT JOIN durations d ON d.event_id_arrival = e.id OR d.event_id_departure = e.id WHERE e.event_time >= :v_limit_date AND e.device_type IN (1, 2) AND e.event_type = 2 AND e.manufacturer LIKE 'XX%' AND d.id IS NULL ) SELECT CURRENT_TIMESTAMP(), arrived_entry.id, departed_entry.id, arrived_entry.event_time, departed_entry.event_time, arrived_entry.card_nr, arrived_entry.ticket_type, DATEDIFF('second', arrived_entry.event_time, departed_entry.event_time), arrived_entry.manufacturer, arrived_entry.carpark_id FROM (SELECT * FROM cte WHERE device_type = 1) AS arrived_entry INNER JOIN (SELECT * FROM cte WHERE device_type = 2) AS departed_entry ON arrived_entry.card_nr = departed_entry.card_nr AND arrived_entry.carpark_id = departed_entry.carpark_id AND arrived_entry.rn + 1 = departed_entry.rn; -- 更新配置表的截止日期 SELECT MAX(event_time) INTO v_max_event_time FROM events WHERE event_time >= :v_limit_date; UPDATE properties SET PROP_VALUE = DATEADD('day', -1 * :v_limit_days, :v_max_event_time)::VARCHAR WHERE PROP_KEY = 'DURATION.LIMIT.DATE'; RETURN '执行成功,已计算最新停车时长记录'; END; $$;
使用方法
每日导入事件数据后,执行以下命令即可完成计算:
CALL calculateDuration();
验证说明
你提供的样例数据执行后,会生成5条符合预期的时长记录,不会出现重复写入问题,properties表的DURATION.LIMIT.DATE会自动按规则更新。
内容的提问来源于stack exchange,提问作者Djabone
相关产品推荐
相关产品推荐

