SQL如何只得到1个真值

SQL How to get only 1 true value

我正在构建一个应用程序,我需要能够唱歌的主唱 我需要防止 2 位老师共享特定 class

的领导头衔
class CreateClassroomTeachers < ActiveRecord::Migration[5.2]
  def change
    create_table :classroom_teachers do |t|
      t.belongs_to :classroom
      t.belongs_to :teacher
      t.boolean    :lead, default: false
    end
    add_index :household_people, [:classroom_id, :teacher_id], unique: true
    # Only one teacher in a classroom can be lead 
  end
end

我的模型中有这个

class ClassroomTeacher < ApplicationRecord
  belongs_to :classroom
  belongs_to :teacher


  validate :only_one_is_lead_teacher

  def only_one_is_lead_teacher
    if lead
      if ClassroomTeacher.where(classroom_id: classroom_id, lead: true).count > 0
        errors.add(:lead, "There can only be one (1) lead teacher per classroom")
      end
    end
  end
end

这里的问题是在 Create 上我可以有 2 个或更多的老师来领导

感谢您的帮助

有几种方法可以通过约束、触发器等实现这一点——取决于您各自的数据库服务器支持什么。

应该 至少在 Postgres 中工作(即使它可能有点 hacky)是在 %i[classroom_id lead] 上设置一个唯一索引并确保 leadtrueNULL。这应该有效,因为 Postgres 将 NULL 值视为不同的,这意味着如果多个 NULL 值存储在具有唯一性约束的列中,它不会抱怨。


如果您想用代码解决它(我个人不建议这样做,因为您的数据库可能会被除您的代码以外的其他东西访问,甚至您的代码也可以绕过它,例如直接写入数据库使用 ActiveRecord 的高级方法),这是我过去的做法:

class ClassroomTeacher < ActiveRecord::Base
  before_save :ensure_only_one_lead_teacher

  private

  def ensure_only_one_lead_teacher
    # We don't have to do this unless the record is the one who should be the (new) lead.
    return unless lead?

    # Set all other records for the class room to lead = false.
    self.class.where(classroom_id: classroom_id).update_all(lead: false)

    # Now if the record gets persisted, it will be the only one with lead = true.
  end
end

一种可能稍微更"correct"的方法是在记录被持久化后确保唯一性:

class ClassroomTeacher < ActiveRecord::Base
  after_commit :ensure_only_one_lead_teacher

  private

  def ensure_only_one_lead_teacher
    # We don't have to do this unless the record is the one who should be the (new) lead.
    return unless lead?

    # Set all other records for the class room to lead = false. Note that we now have to exclude
    # the record itself by id because it has already been saved.
    self.class.where.not(id: id).where(classroom_id: classroom_id).update_all(lead: false)
  end
end

根据迁移,模型的属性是 课堂教师:classroom_id、teacher_id、领导

正在考虑将教师添加到 class:

/控制器文件

def create
  ClassroomTeacher.create(teacher_id: data1, classroom_id: data2, lead: data3)
end

具有理想值的可能样本数据为:

id classroom_id teacher_id lead
1     1             3       false
2     2             4       true
3     1             2       false
4     1             5       true

现在您需要避免将任何新教师作为主管添加到 class房间。模型验证代码可以是

validate :only_one_is_lead_teacher

def only_one_is_lead_teacher
  if self.lead
    class_obj = ClassroomTeacher.where(classroom_id: self.classroom_id, lead: true).first
    if class_obj.present?
      self.errors.add(:lead, "There can only be one (1) lead teacher per classroom")
      return false
    end
  end
end