drop function if exists get_referers(param_user_id bigint, param_user_bm_id smallint) cascade; create function get_referers(param_user_id bigint, param_user_bm_id smallint) returns table ( referer_id bigint, referer_level integer ) as $end$ declare origin_referer_id bigint; origin_level integer; begin SELECT user_bms.user_id, COUNT(*) % 5 + 1 FROM users, user_bms WHERE users.user_id=param_user_bm_id AND user_bms.user_id=users.referer_id AND user_bms.bm_id=param_user_bm_id GROUP BY user_bms.user_id INTO origin_referer_id, origin_level; -- SELECT users.referer_id -- FROM users -- WHERE users.user_id = param_user_id -- INTO origin_referer_id; -- -- SELECT COUNT(*) % 5 + 1 -- FROM user_bms -- WHERE -- user_bms.user_id=origin_referer_id -- AND -- user_bms.bm_id=param_user_bm_id -- INTO origin_level; -- return query with recursive tree as ( select origin_referer_id as referer_id, origin_level as referer_level union select users.referer_id as referer_id, tree.referer_level::integer - case when user_bms.user_id is null then 0 else 1 end as referer_level from users left join user_bms on user_bms.user_id = users.user_id and user_bms.bm_id = param_user_bm_id join tree on tree.referer_id = users.user_id and users.user_id != users.referer_id where tree.referer_level - case when user_bms.user_id is null then 0 else 1 end >= 0 ) select tree.referer_id, origin_level from tree order by tree.referer_level limit 1; end; $end$ language plpgsql; select * from get_referers(1122::bigint, 1::smallint);