MySQL: 你如何查询复合主键?具体来说,一个 NOT IN 查询?
MySQL: How do you query on a compound-primary-key? Specifically, a NOT IN query?
我有一个comment
table和一个comment_edit
table,还有olddb_edit
。简化后,相关的 table 看起来像这样:
CREATE TABLE `olddb_edit` (
edit_id INT NOT NULL,
edit_time INT NOT NULL,
edit_text TEXT NOT NULL,
PRIMARY KEY (edit_id, edit_time)
) ENGINE=InnoDB;
现在我想将内容从另一个数据库迁移到编辑-table,但跳过一些 table-行,例如测试评论。为此,我正在使用 CakePHP(实际上是 Phinx)。
通常,这就足够了:
$skippable = array(
12345, 23456, 34567, 45678,
);
$rows = $this->getQueryBuilder()
->select('*')
->from('olddb_comment')
->where(array(
'comment_id NOT IN' => $skippable,
))
->execute()
->fetchAll('assoc')
;
但是一个简单的 NOT IN
子句显然不适用于复合主键。
我在想,$skippable
数组应该是这样的:
$skippable = array(
array('id' => 707969, 'time' => 1434462225),
array('id' => 707969, 'time' => 1434462463),
array('id' => 707969, 'time' => 1434462551),
);
然后我将 运行 通过 for 循环或其他方式的 where 子句。但老实说,我什至不知道如何在原版中做到这一点-MySQL.
可能已经在 SO 上发布了解决方案,但我找不到任何解决方案(除了特定于其他应用程序的解决方案)。我猜算法不是我的朋友。
没关系,我在制定问题时自己想出来了。无论如何,我都会 post 回答其他有类似问题的人。
首先,香草-MySQL。如果您分解 NOT IN
(imo):
,它就像您想象的一样直观
SELECT * FROM olddb_edit WHERE
NOT (
(edit_id = 707969 AND edit_time = 1434461454)
OR (edit_id = 707969 AND edit_time = 1434461503)
OR (edit_id = 707969 AND edit_time = 1434461925)
);
对于 CakePHP / Phinx 查询生成器,您可以使用匿名函数、for 循环和 not-or 结构:
$qb = $this->getQueryBuilder()
->select('*')
->from('olddb_edit')
->where(array(
'edit_some_other_optional_condition = 1',
))
// also skip skippables.
->where(function($exp) use ($skippable) {
$ORed = array();
foreach ($skippable as $edit) {
array_push($ORed, array(
'edit_id' => $edit['id'],
'edit_time' => $edit['time'],
));
}
return $exp->not($exp->or_($ORed));
})
;
更新: 根据@ndm 的评论,我提出了一个使用 TupleComparison 的令人满意的解决方案。 —(@ndm,如果您愿意,请随时 post 您的答案。我会 delete/edit 我的,然后选择您的。您应得的荣誉)。
// remove the keys from my previous solution.
$skippable = array(
array(707969, 1434462225),
array(707969, 1434462463),
array(707969, 1434462551),
);
$qb = $this->getQueryBuilder()
->select('*')
->from('olddb_edit')
->where(array(
'edit_some_other_optional_condition = 1',
))
// also skip skippables.
->where(new Cake\Database\Expression\TupleComparison(
array('edit_id', 'edit_time'),
$skippable,
array('integer', 'integer'),
'NOT IN'
))
;
您的查询评估如下;你确定那是你想要的吗?
select edit_id
, edit_time
, edit_text
from olddb_edit
where
(
(
(edit_id <> 707969)
or (edit_time <> 1434461454)
)
and (
(edit_id <> 707969)
or (edit_time <> 1434461503)
)
and (
(edit_id <> 707969)
or (edit_time <> 1434461925)
)
);
我有一个comment
table和一个comment_edit
table,还有olddb_edit
。简化后,相关的 table 看起来像这样:
CREATE TABLE `olddb_edit` (
edit_id INT NOT NULL,
edit_time INT NOT NULL,
edit_text TEXT NOT NULL,
PRIMARY KEY (edit_id, edit_time)
) ENGINE=InnoDB;
现在我想将内容从另一个数据库迁移到编辑-table,但跳过一些 table-行,例如测试评论。为此,我正在使用 CakePHP(实际上是 Phinx)。
通常,这就足够了:
$skippable = array(
12345, 23456, 34567, 45678,
);
$rows = $this->getQueryBuilder()
->select('*')
->from('olddb_comment')
->where(array(
'comment_id NOT IN' => $skippable,
))
->execute()
->fetchAll('assoc')
;
但是一个简单的 NOT IN
子句显然不适用于复合主键。
我在想,$skippable
数组应该是这样的:
$skippable = array(
array('id' => 707969, 'time' => 1434462225),
array('id' => 707969, 'time' => 1434462463),
array('id' => 707969, 'time' => 1434462551),
);
然后我将 运行 通过 for 循环或其他方式的 where 子句。但老实说,我什至不知道如何在原版中做到这一点-MySQL.
可能已经在 SO 上发布了解决方案,但我找不到任何解决方案(除了特定于其他应用程序的解决方案)。我猜算法不是我的朋友。
没关系,我在制定问题时自己想出来了。无论如何,我都会 post 回答其他有类似问题的人。
首先,香草-MySQL。如果您分解 NOT IN
(imo):
SELECT * FROM olddb_edit WHERE
NOT (
(edit_id = 707969 AND edit_time = 1434461454)
OR (edit_id = 707969 AND edit_time = 1434461503)
OR (edit_id = 707969 AND edit_time = 1434461925)
);
对于 CakePHP / Phinx 查询生成器,您可以使用匿名函数、for 循环和 not-or 结构:
$qb = $this->getQueryBuilder()
->select('*')
->from('olddb_edit')
->where(array(
'edit_some_other_optional_condition = 1',
))
// also skip skippables.
->where(function($exp) use ($skippable) {
$ORed = array();
foreach ($skippable as $edit) {
array_push($ORed, array(
'edit_id' => $edit['id'],
'edit_time' => $edit['time'],
));
}
return $exp->not($exp->or_($ORed));
})
;
更新: 根据@ndm 的评论,我提出了一个使用 TupleComparison 的令人满意的解决方案。 —(@ndm,如果您愿意,请随时 post 您的答案。我会 delete/edit 我的,然后选择您的。您应得的荣誉)。
// remove the keys from my previous solution.
$skippable = array(
array(707969, 1434462225),
array(707969, 1434462463),
array(707969, 1434462551),
);
$qb = $this->getQueryBuilder()
->select('*')
->from('olddb_edit')
->where(array(
'edit_some_other_optional_condition = 1',
))
// also skip skippables.
->where(new Cake\Database\Expression\TupleComparison(
array('edit_id', 'edit_time'),
$skippable,
array('integer', 'integer'),
'NOT IN'
))
;
您的查询评估如下;你确定那是你想要的吗?
select edit_id
, edit_time
, edit_text
from olddb_edit
where
(
(
(edit_id <> 707969)
or (edit_time <> 1434461454)
)
and (
(edit_id <> 707969)
or (edit_time <> 1434461503)
)
and (
(edit_id <> 707969)
or (edit_time <> 1434461925)
)
);