我正在使用CakePHP 2.x而且我经常遇到我想要将记录添加到连接表的情况,但我想确保相同的“连接”记录不存在。
具体而言,这是一个基本的例子......
模特:学生有和贝伦到多个课程 型号:课程有和贝伦到多个学生 加入Table = courses_students并有字段“student_id”和“course_id”
假设我有一个学生的表格,我希望与课程相关联。表单向控制器提交了一堆student_id。在我添加新记录之前,我需要确保记录不存在(因为您不能两次注册相同的课程)。这是事情变得混乱的地方......
选项1:我有时为连接表中每个(可能)预先存在的记录构建一个deleteAll(),该记录包含当前的course_id和任何提交的user_id。这是有效的,但缺点是它会删除可能存储在其他字段中的任何预先存在的数据,例如日期等。
选项2:我有时会遍历每个提交的记录,并为每个(可能)预先存在的记录执行find()。这允许我保留现有记录,但对数据库进行了大量额外查询。
这是我通常处理这种情况的两种方式,但我怀疑有更好的方法。它是什么?
答案 0 :(得分:0)
您可以使用REPLACE INTO
。例如:
REPLACE INTO courses_students (course_id, student_id, when)
VALUES (1, 2, 12345678)
哪个会用新值覆盖列when
。我确信在纯SQL中有一种方法可以不这样做:http://dev.mysql.com/doc/refman/5.0/en/replace.html
也不确定它在CakePHP中的作用。他们的DBAL可能有数据库合并的帮助。
(MySQL不支持MERGE INTO .. WHEN MATCHED
,所以你必须先做SELECT然后INSERT。)
(顺便说一下:选项2效率不高,因为你已经为course_id
+ student_id
创建了一个复合的唯一键。SELECT
将非常快。)< / p>
修改强>
如果您正确地索引列,SELECT
非常非常快且便宜。表courses_students
应该在(course_id, student_id)
上有一个PK。如果您担心查询的数量,可以在1个查询中执行所有SELECT:
:ids from input
SELECT course_id, student_id FROM courses_students WHERE course_id IN (:ids) AND student_id IN (:ids)
然后将它们映射到一个assoc可访问的数组:
array(course_id => array(student_id => TRUE))
然后循环输入(POST?)并过滤现有记录:
if ( !isset($map[$course_id][$student_id]) ) {
// INSERT HERE
}
总共count(INPUT) + 1
个查询。
但所有这些都是很多代码。您可以循环查询每条记录。我保证它很便宜。