Warning: file_get_contents(/data/phpspider/zhask/data//catemap/5/sql/75.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
使用Perl DBI跨两个表删除Mysql重复行_Mysql_Sql_Database_Perl_Dbi - Fatal编程技术网

使用Perl DBI跨两个表删除Mysql重复行

使用Perl DBI跨两个表删除Mysql重复行,mysql,sql,database,perl,dbi,Mysql,Sql,Database,Perl,Dbi,在我看来,这是一个非常好的例子,我还没有在SO或Google上看到过一个类似的例子。我需要在正在构建的Perl应用程序中执行以下操作。不幸的是,它不能直接在MySQL中完成,需要DBI。简而言之,我需要获取Database1.tableA并找到每个列“status”匹配“started”的记录。我可以这样做,因为这相当容易(DBI还不是很好,但已经阅读了文档),但我遇到的问题是我下一步要做的事情 my $started_query = "SELECT primary_ip FROM queue

在我看来,这是一个非常好的例子,我还没有在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数组中的每个记录,实际上while循环的每次迭代只包含一个值,我需要查看它是否存在于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来连接两个数据库,目前我无法理解逻辑。我可以对两个数据库进行查询并存储在@array中,然后进行比较,但这似乎是多余的,因为我认为在
while(my@started=$started->fetchrow_array())
中应该可以这样做,因为这样可以节省运行时和所需的资源。我还不太熟悉在DBI实例之间传递变量,因为@started数组总是包含我需要查询和删除的列值,所以我想充分利用定义并传递给DBI对象的优势


我整晚都在做这件事,已经喝了几壶咖啡,所以非常感谢你帮助我理解这个逻辑

使用fetchrow_hashref会更好,它返回键/值对的hashref,其中键是列名,而不是基于数组中顺序位置显示的列进行编码

您需要一个额外的数据库句柄来进行查找和更新,因为在第一个数据库句柄上有一个live语句句柄。大概是这样的:

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永远不会为空”。。。在没有匹配行的左连接中,它是null

然后,从t1中删除行也可以通过连接完成。多表联接仅从
delete
from
之间列出的表别名中删除行。同样,我们用别名“a”调用“t1”,用别名“b”调用“t2”


这将删除t1(“a”)中状态为“已启动”且t2中存在匹配行的每一行。

Database2.tableA是否比Database1.tableA大得多?如果没有,您几乎肯定会更好,只需将PK列表从Database2.tableA导出到一个文件,将其导入Database1中的一个表,然后使用两个查询(a
DELETE
和a
UPDATE
,以任意顺序)连接到此表。连接到这两个数据库时使用的凭据是否相同?它们在同一台服务器上吗?我这样问是因为MySQL使用了术语“数据库”来表示ANSI SQL所称的“模式”——如果您的数据库是真正的模式,那么SQL可以完成繁重的工作。同一台服务器不同的用户和不同的数据库,但我必须使用DBI,因为我们在这里的骆驼湾。我最近扣动了扳机,差点被烧死在火刑柱上…@Micheal你的回答很有道理。我需要运行一些测试,但最初它看起来很可靠。我希望DBA能做出回应,因为你们总是拥有最好的东西。再次感谢,伙计。测试很好——不要相信我在您的实时系统上给出的答案。:)但如果我理解您的需求,并且没有转置太多的表名,这应该可以让您接近。
DELETE a
  FROM db1.t1 a JOIN db2.t2 b ON a.primary_ip = b.primary_ip
 WHERE a.status = 'started';