[英]Rails and queries - Custom query to get duplicated records
在大多数情况下,我尽量不使用我的应用程序编写自定义SQL查询,但我错了一个案子,我想知道这是否是我最好做的情况。
我在这个特定的应用程序中使用PostgreSQL。 我只想返回被双重预定任务的员工,这是我的模型。
我有以下型号的波纹管。
用户
has_many :user_jobs
Fields
- id
- name
- address
- phone
工作
has_many :user_jobs
has_many :users, through: :user_jobs
Fields
- id
- date
- start_time
- end_time
UserJobs
belongs_to :user
belongs_to :jobs
Fields
- id
- job_id
- user_id
Userjobs是保存工作和该工作的雇员的表,但是每个工作的日期和时间都保存在Job表中
我想返回类似
user(employee) - date and time job1 - date and time job1
编辑:添加了更多架构详细信息
CREATE TABLE user_jobs (
id integer NOT NULL,
job_id integer,
job_date date,
notes text,
job_rating integer,
notes text,
created_at timestamp without time zone,
updated_at timestamp without time zone,
user_id integer,
);
CREATE TABLE jobs (
id integer NOT NULL,
date date,
start_time time without time zone,
end_time time without time zone,
notes text,
);
CREATE TABLE users (
id integer NOT NULL,
email character varying(255) DEFAULT ''::character varying NOT NULL,
name character varying(255),
address character varying(255),
phone character varying(255),
picture character varying(255),
status character varying(255) DEFAULT 'active'::character varying,
);
提前致谢
Postgres 9.2以上
这有点陈旧:
WITH alljobs AS(
SELECT * FROM jobs j INNER JOIN user_jobs uj ON uj.job_id = j.id
)
SELECT DISTINCT q1.user_id
FROM alljobs q1
JOIN alljobs q2 on
q1.user_id = q2.user_id
AND tsrange(q1.date + q1.start_time, q1.date + q1.end_time) && tsrange(q2.date + q2.start_time, q2.date + q2.end_time)
说明:
WITH alljobs
有效地将变量名称alljobs
分配给给定查询。 该查询只是所有作业分配的合并列表,包括开始时间和结束时间。 SELECT DISTINCT q1.user_id
仅返回被重复预订的用户的ID。 从技术上讲,这是您所要的,尽管您可能希望扩展此选择以获取更多有用的信息。 我建议在调试时使用SELECT *
。 FROM alljobs q1 JOIN alljobs q2
这将作业与自身进行联接,这是将每个作业与其他作业进行比较所必需的。 q1.user_id = q2.user_id
我们只关心单个用户的冲突。 如果您想回答诸如“谁在一起工作?”之类的相关问题,则可以更改此设置。 tsrange
一个postgres内置范围函数 ,该函数从两个时间戳创建一个范围。 日期和其他类型的时间戳具有类似的功能。 _这些范围类型仅在9.2中引入。 &&
一个postgres范围运算符,用于交集。 Postgres <9.2
您可以使用自己的交集逻辑替换tsrange
和&&
,我认为它类似于: q1.start_time < q2.start_time && q1.finish_time > q2.start_time OR q2.start_time < q1.start_time && q2.finish_time > q1.start_time
。 (以及添加date
。)
或者,由于您指定的开始时间始终是相同的,而且实际上这就是您关心的全部,因此在这种情况下,您可以做一些简单的事情:
SELECT user_id, date + start_time, COUNT(*)
FROM user_jobs INNER JOIN jobs ON job_id = jobs.id
GROUP BY user_id, date + start_time
HAVING COUNT(*) > 2
这将为您提供所有重复的用户ID。 要获取相应的作业,可以将其包装在外部查询中。
SELECT user_jobs.user_id, user_jobs.job_id, jobs.date + jobs.start_time
FROM user_jobs INNER JOIN jobs ON job_id = jobs.id INNER JOIN (
SELECT user_id, date + start_time, COUNT(*)
FROM user_jobs INNER JOIN jobs ON job_id = jobs.id
GROUP BY user_id, date + start_time
HAVING COUNT(*) > 2
) dups ON dups.user_id = user_jobs.user_id
AND dups.date + dups.start_time = job.date + jobs.start_time
模式建议
通过使用单独的date
和time
列,您将使自己的生活更加困难。 为什么不仅仅设置start_time
和end_time
时间戳? 然后,您不必总是将它们加在一起,并且仍然可以通过强制转换获得日期。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.