【问题标题】:ActiveRecord/SQL: Complex DB query (outer_join / union / ?)ActiveRecord/SQL:复杂的数据库查询(outer_join / union / ?)
【发布时间】:2021-03-20 19:55:49
【问题描述】:

数据库查询:我想对培训的所有参与者进行 ONE 数据库查询,显示所有参与者的姓名以及他们是否已经拥有这项一项特定技能。为了构建结果表(参见示例),我想循环查询结果,而不必为每个员工进行子查询。

|participant name|has_this_one_specific_skill|
|John Doe        |          yes              |
|Alex Hardacre   |          yes              |
|Abi Underwood   |          no               |
|Kevin Wallace   |          yes              |
|Connor Murray   |          no               |

这是我的数据库结构。这样的结构会是什么样子?这是 left_outer_join 还是我要加入 union?

【问题讨论】:

  • 它将通过employees_skills 表与技能表进行外部连接。但是先告诉我一件事,当你说‘他们是否已经有某种技能’时,你的意思是你只想检查特定的单一技能吗? i-e 招募所有员工,无论他们是否具有 MYSQL 技能(鉴于技能表中有 MYSQL 技能)
  • @QaisarNadeem:正确。我只想检查特定技能。员工可以有很多技能。我想展示的是,员工是否已经具备在培训中“训练”过的技能
  • 你的Participant class看起来不对,我想你的意思是:它是员工和培训之间的桥梁,对吧?如果是,那么它应该有belongs_to :employee & belongs_to :training ??
  • @QaisarNadeem:是的,当然。对不起,复制和过去的错误。会更新。
  • 好的,我会为你写一个查询。只需确认您的数据库是什么,是 MYSQL 还是 POSTGRESQL?

标签: sql ruby-on-rails ruby activerecord


【解决方案1】:
class Employee < ApplicationRecord
  has_many :participants
  has_many :trainings,through: :participants
  has_many :trained_skills,through: :trainings,source: :skill
end



class Training < ApplicationRecord
  belongs_to :skill
end


class Participant < ApplicationRecord
  belongs_to :training
  belongs_to :employee
end

解决方案 1 - 推荐

   Employee.left_joins(:trained_skills).where({skills: {name: ["MYSQL",nil]}}).pluck "employees.name,CASE WHEN skills.id IS NOT NULL THEN 'yes' else 'no' end"

注意:如果您需要员工对象,您可以使用select 而不是pluck。即######.select "employees.name as participant_name,CASE WHEN skills.id THEN 'yes' else 'no' end as has_this_one_specific_skill"

解决方案 2

 Employee.joins("LEFT OUTER JOIN participants
  ON participants.employee_id = employees.id LEFT OUTER JOIN trainings
  ON trainings.id = participants.training_id LEFT OUTER JOIN skills
  ON skills.id = trainings.skill_id AND skills.name = 'MYSQL'").
  pluck "employees.name,CASE WHEN skills.id IS NOT NULL THEN 'yes' else 'no' end"

【讨论】:

  • 几乎即插即用的解决方案。对于 pluck,我得到了一个“PG::DatatypeMismatch:错误:CASE/WHEN 的参数必须是布尔类型,而不是 bigint 类型”。必须更改为以下内容:“... CASE WHEN Skills.id IS NOT NULL ...”。你想更新吗?
  • 对于方案一,这实际上只返回已经具备技能的员工,而不是没有技能的员工。查看 SQL ActiveRecord 生成: SELECT * FROM "employees" INNER JOIN "participants" ON "employees"."id" = "participants"."employee_id" LEFT OUTER JOIN "employee_skills" ON "employee_skills"."employee_id" = " employees"."id" WHERE "participants"."training_id" = $1 AND ("employee_skills"."skill_id" IN (1,4) OR "employee_skills"."skill_id" 为空。你会注意到,这是一个与解决方案 2 有点不同,它提供了预期的结果!
猜你喜欢
  • 2021-11-06
  • 1970-01-01
  • 2023-02-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-08-05
  • 2021-11-27
相关资源
最近更新 更多