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]
上设置一个唯一索引并确保 lead
是 true
或 NULL
。这应该有效,因为 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
我正在构建一个应用程序,我需要能够唱歌的主唱 我需要防止 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]
上设置一个唯一索引并确保 lead
是 true
或 NULL
。这应该有效,因为 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