2016-08-23 49 views
3

在CakePHP 3删除滤波,假设我想删除所有部门有一些员工命名为“约翰”(部门有多少员工,员工所属部门CakePHP的3通过相关数据

最简单的方法是过滤所有的部门,并在foreach循环删除它们一个接一个:

$departments = $this->Departments->find() 
    ->matching('Employees', function ($q) { 
     return $q->where(['Employees.name' => 'John']); 
    }) 
    ->all(); 

foreach ($departments as $department) { 
    $this->Departments->delete($department); 
} 

这将导致一个SELECT查询加上每条记录DELETE查询。我希望只有一个查询被数据库发送和执行。事情是这样的:

DELETE Departments 
FROM departments Departments 
INNER JOIN employees Employees ON 
    Employees.department_id = Departments.id 
    AND Employees.name = 'John'; 

阅读中,我发现三种方式来删除记录文档:

有没有一种优雅的方式来使用CakePHP 3和ORM获取我的查询?

回答

0

deleteAll只是围绕

$this->Departments->query() 
    ->delete() 
    ->where([...]) 
    ->execute(); 

一个包裹所以我虽然是,以类似的方式,将有可能做到:

$departments = $this->Departments->query() 
    ->delete() 
    ->matching('Employees', function ($q) { 
     return $q->where(['Employees.name' => 'John']); 
    }) 
    ->execute(); 

但在这种情况下,你会发现,匹配条件被忽略。我看到有一个开放的ticket有关

如果你想只使用两个查询,你可以做一个查询检索所有的ID和删除所有在第二个查询:

$departments_ids = $this->Departments->find() 
    ->select(['id']) 
    ->matching('Employees', function ($q) { 
     return $q->where(['Employees.name' => 'John']); 
    }) 
    ->toArray(); 

$this->Departments->deleteAll(['id' => $departments_ids ]); 

导致在类似的东西:

DELETE FROM departments WHERE id IN 
(
    // id list here 
) 

另一种解决方案可以将您的内部联接转换为子查询。实际上你想要删除几乎有一个名为John的员工的所有部门。

$employees = $this->Departments->Employees->find() 
    ->select(['department_id']) 
    ->distinct() 
    ->where(['Employees.name' => 'John']); 

$departments = $this->Departments->query() 
    ->delete() 
    ->where(['id IN' => $employees]) 
    ->execute(); 
+0

谢谢@arilia。实际上,为了获得这个查询,你应该把''id'=> $ departments'改成''id IN'=> $ departments',否则你得到的是一个等号“=”。另一方面,该查询返回[1093 mysql错误](http://stackoverflow.com/questions/45494/mysql-error-1093-cant-specify-target-table-for-update-in-from-条款)。 – pperejon

+0

无论如何,根据[文档](http://dev.mysql.com/doc/refman/5.6/en/update.html),生成的SQL查询仍然是错误的,他们说_您无法更新表并从中进行选择子查询中的同一张表._ – pperejon

+0

我对此不了解。我将编辑或删除我的答案 – arilia

0

两件事情:

第一:我建议的方案是不正确

我的真实情况要复杂得多,所以我做了著名的员工部门为例的情况。我犯了一个错误:我需要的是删除属于某个部门的所有员工。我想从相关表的基于表的条件中删除数据。

事实上,你不能删除有雇员姓名约翰的部门,因为部门不是空的,还有约翰! :d

事情是这样的:

-- Create structures 
CREATE TABLE IF NOT EXISTS departments (
    id int(11) NOT NULL AUTO_INCREMENT, 
    name varchar(45) NOT NULL, 
    PRIMARY KEY (id) 
) ENGINE=InnoDB DEFAULT CHARSET=utf8 AUTO_INCREMENT=4 ; 

CREATE TABLE IF NOT EXISTS employees (
    id int(11) NOT NULL AUTO_INCREMENT, 
    department_id int(11) NOT NULL, 
    name varchar(45) NOT NULL, 
    PRIMARY KEY (id), 
    KEY fk_employees_department_idx (department_id) 
) ENGINE=InnoDB DEFAULT CHARSET=utf8 AUTO_INCREMENT=5 ; 

ALTER TABLE employees 
    ADD CONSTRAINT fk_employees_departments FOREIGN KEY (department_id) REFERENCES departments (id) ON DELETE NO ACTION ON UPDATE NO ACTION; 


-- Populate some data 
INSERT INTO departments (id, name) VALUES 
(1, 'Sales'), 
(2, 'TI'), 
(3, 'HHRR'); 

INSERT INTO employees (id, department_id, name) VALUES 
(1, 1, 'John'), 
(2, 1, 'Mary'), 
(3, 2, 'Mark'), 
(4, 3, 'Lorenzo'); 


-- Delete all employees that belong to the TI department (Mark should be removed) 
DELETE emp FROM employees emp 
INNER JOIN departments dep ON emp.department_id = dep.id AND dep.name = 'TI'; 

第二:你可以在CakePHP中做到这一点很容易

你可以得到以前的查询相同的结果这样做:

$departments = $this->Employees->Departments->find() 
     ->select(['Departments.id']) 
     ->where(['Departments.name' => 'TI']); 
    $this->Employees->deleteAll(['Employees.department_id IN' => $departments]); 

由此产生的MySQL查询将是:

DELETE FROM employees WHERE department_id in 
(SELECT Departments.id AS `Departments__id` 
FROM departments Departments 
WHERE Departments.name = 'TI') 

......这是正确的,而且容易理解。 @arilia,你用第一个答案指出了这个方向。对不起,我对此深表歉意。