这个是一个相当不错的IMO,我还没有在SO或Google上看过一个很好的例子,所以你走了。我需要在我正在构建的Perl应用程序中执行以下操作。不幸的是,它不能直接在MySQL中完成,需要DBI。简而言之,我需要使用Database1.tableA并找到列'status'匹配'started'的每条记录。我可以这样做,因为它相当容易(DBI还不是很好,但已阅读过文档),但我遇到问题的地方就是我接下来要做的事情。
my $started_query = "SELECT primary_ip FROM queue WHERE status='started'";
my $started = $dbh->prepare($started_query);
$started->execute();
while ( my @started = $started->fetchrow_array() ) {
# Where I am hoping to have the following occur so it can go by row
# for only rows with the status 'started'
}
因此对于@started数组中的每个记录,实际上每次迭代时只包含一个值,我需要查看它是否存在于Database2.tableA中,如果它存在于另一个数据库中(Database2.tableA)我需要从Database1.tableA中删除它,但如果它不存在于其他数据库(Database2.tableA)中,我需要更新当前数据库中的记录(Database1.tableA)。
基本上复制以下半有效的MySQL语法。
DELETE FROM tableA WHERE primary_ip IN (SELECT primary_ip FROM db2.tablea) OR UPDATE tableA SET status = 'error'
我仅限于DBI连接到两个数据库,逻辑正在逃避我。我可以对两个数据库进行查询并存储在@arrays中然后进行比较,但这似乎是多余的,因为我认为它应该可以在while ( my @started = $started->fetchrow_array() )
内,因为这将节省运行时和所需的资源。我也不熟悉在DBI实例之间传递变量,因为@started数组总是包含我需要查询和删除的列值我想充分利用已定义并传递给DBI对象。< / p>
我将整晚都在做这件事并且已经经历了几罐咖啡,所以你帮助我理解这个逻辑非常感谢。
答案 0 :(得分:1)
你最好使用fetchrow_hashref,它返回键/值对的hashref,其中键是列名,而不是根据显示在数组中序数位置的列进行编码。
您需要一个额外的数据库句柄来执行查找和更新,因为您在第一个上有一个实时语句句柄。像这样:
my $dbh2 = DBI->connect(...same credentials...);
...
while(my $row = $started->fetchrow_hashref)
{
if(my $found = $dbh2->selectrow_hashref("SELECT * FROM db2.t2 WHERE primary_ip = ?",undef,$row->{primary_ip}))
{
$dbh2->do("DELETE FROM db1.t1 WHERE primary_ip = ?",undef,$found->{primary_ip});
}
else
{
$dbh2->do("UPDATE db1.t1 SET status = 'error' WHERE primary_ip = ?",undef,$found->{primary_ip}");
}
}
从技术上讲,我“不需要”从db2.t2获取行到my $found
,因为你只是在测试存在,还有其他方法,但在这里使用它是一点保险反对做一些你想要的事情,因为如果我们以某种方式得到一些错误的逻辑并且这应该阻止我们做出一些潜在的错误改变,那将是不确定的。
但是使用循环迭代来接近关系数据库很少是最好的策略。
只需要几个查询就可以直接在MySQL中完成。
首先,更新,其中t1.status ='started'和t2.primary_ip没有t1.primary_ip的匹配值:
UPDATE db1.t1 a LEFT JOIN db2.t2 b ON b.primary_ip = a.primary_ip
SET a.status = 'error'
WHERE b.primary_ip IS NULL AND a.status = 'started';
如果您正在考虑“但b.primary_ip永远不会为空”...好吧,在没有匹配行的左连接中它为空。
然后从连接中删除t1中的行也可以完成。多表连接仅删除DELETE
和FROM
之间列出的表别名中的行。同样,我们用别名“a”调用“t1”,用别名“b”调用t2。
DELETE a
FROM db1.t1 a JOIN db2.t2 b ON a.primary_ip = b.primary_ip
WHERE a.status = 'started';
这将删除t1(“a”)中的每一行,其中status ='started'并且t2中存在匹配的行。