来自某个SELECT语句的重复数据

后端开发 2026-07-11

我正在用PostgreSQL创建一个根据用户姓名来查询数据的函数,但当参数中没有传入姓名时,它应该返回所有预约,且不受姓名影响;然而我却得到了重复的数据。因为只有John Doe与之相关的预约存在,这个Ian F不应该出现在结果中。

姓名 时长 预约时间
John Doe 50 2026-03-24 10:00:00
Ian F 50 2026-03-24 10:00:00

正如你所见,数据被重复了,因为Ian F没有任何预约,他只是复制了John Doe的数据。由于我不知道在PostgreSQL中如何调试,我也不太清楚这是为什么。

该函数。

CREATE or replace FUNCTION get_appointment(customerName varchar, companyNickname varchar) RETURNS TABLE (name varchar, duration int, scheduled timestamp)
as $$
BEGIN 
    IF customerName is null OR TRIM(customerName) = '' THEN
        return query
            SELECT c.user_name, d.service_duration, b.scheduled_time from company_tb a 
                join schedules_tb b on a.id = b.company_id
                join users_tb c on a.id = c.company_id
                join services_tb d on a.id = d.company_id
                where b.service_id = d.id
                and a.company_nickname = companyNickname
                and b.scheduled_time > CURRENT_TIMESTAMP;
    ELSE
         return query
            SELECT c.user_name, d.service_duration, b.scheduled_time from company_tb a 
                join schedules_tb b on a.id = b.company_id
                join users_tb c on a.id = c.company_id
                join services_tb d on a.id = d.company_id
                where b.service_id = d.id
                and c.user_name = customerName
                and a.company_nickname = companyNickname
                and b.scheduled_time > CURRENT_TIMESTAMP;
    END IF;
END
    $$LANGUAGE plpgsql;

SELECT * from get_appointment('', 'agendaai-barber');

表的定义和数据。

company_tb

创建时间 ID 名称 昵称 方案
2026-03-23 16:11:08 1 AgendaAI Barber Shop agendaai 免费

schedules_tb b

公司ID 客户ID ID 日程 服务ID 用户ID
1 1 1 2026-03-24 10:00:00 1 1
1 2 2 2026-03-24 11:00:00 3 1
1 3 3 2026-03-24 12:00:00 1 1
1 4 4 2026-03-24 15:00:00 1 1
1 5 5 2026-03-25 08:00:00 2 1
1 6 6 2026-03-25 10:00:00 1 1
1 7 7 2026-03-26 10:00:00 1 1

users_tb

公司ID ID 创建时间 邮箱 姓名 角色
1 1 2026-03-24 10:00:00 email@mail John Doe ADM
1 2 2026-03-24 11:00:00 email@mail Ian F USER

services_tb

时长 价格 ID 公司ID 描述 名称
60 40 1 1 经典男士理发 理发
20 20 2 1 胡须修剪 胡须修剪

解决方案

你在 schedules_tb.user_idusers_tb.id 之间缺少一个连接条件。

此外,这个函数也可能更适合作为一个普通的 sql 函数,而不是 pgpsql,这将便于内联。你还应该使用比a、b、c更易理解的别名,并给表命名为 _tb,这确实有点麻烦。

CREATE or replace FUNCTION get_appointment
  (customerName varchar, companyNickname varchar)
RETURNS TABLE (name varchar, duration int, scheduled timestamp)
as $$
    SELECT
      u.name,
      sv.duration,
      sc.schedule
    from company_tb c
    join schedules_tb sc on c.id = sc.company_id
    join users_tb u on c.id = u.company_id and sc.user_id = u.id
    join services_tb sv on c.id = sv.company_id and sc.service_id = sv.id
    where customerName <> ''
      and u.name = customerName
      and c.nickname = companyNickname
      and sc.schedule > CURRENT_TIMESTAMP

    UNION ALL

    SELECT
      u.name,
      sv.duration,
      sc.schedule
    from company_tb c
    join schedules_tb sc on c.id = sc.company_id
    join users_tb u on c.id = u.company_id and sc.user_id = u.id
    join services_tb sv on c.id = sv.company_id and sc.service_id = sv.id
    where (customerName is null or customerName = '')
      and c.nickname = companyNickname
      and sc.schedule > CURRENT_TIMESTAMP;
    $$LANGUAGE sql;

db<>fiddle

站内所有文章版权归属LeftHeroAI导航站,无授权禁止任何主体转载、抄袭、复制内容,亦不得私自架设镜像站点。一经侵权,本站将通过法律途径追责。

相关文章