2013-10-29 32 views
0

這是一個很不錯的IMO,我還沒有在SO或Google上看到一個關閉的例子,所以在這裏你去。我需要在我正在構建的Perl應用程序中執行以下操作。不幸的是,它不能直接在MySQL中完成,並且需要DBI。簡而言之,我需要使用Database1.tableA,並找到與「開始」匹配的「狀態」列的每條記錄。我可以這樣做,因爲它很容易(DBI不太好,但已經閱讀過文檔),但是我遇到的問題是我接下來要做的。跨兩個表的Perl DBI Mysql重複行刪除

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連接到兩個數據庫,邏輯當前正在逃避我。我可以對兩個數據庫執行查詢並存儲在@arrays中,然後進行比較,但似乎是多餘的,因爲我認爲它應該可以在while (my @started = $started->fetchrow_array())之內,因爲這樣可以節省運行時和所需的資源。我還沒有與DBI實例之間並作爲@started陣列將始終包含列值,我需要查詢和刪除我想借此具有定義並傳遞給DBI對象的充分利用傳遞變量足夠熟悉。

我將要在這件事上所有的夜晚工作,並已通過的咖啡壺情侶跑讓你幫助我明白這個邏輯是極大的讚賞。

+0

Database2.tableA比Database1.tableA大得多嗎?如果沒有,你幾乎肯定會更好,只需將Databases.tableA中的PKS列表導出到文件中,將它導入到Database1中的表格中,然後使用2個查詢(一個'DELETE'和一個'UPDATE',以任意順序)加入到此表中。 –

+0

用於連接到兩個數據庫的憑證是否相同?他們在同一臺服務器上嗎?我問,因爲MySQL使用術語「數據庫」來表示什麼ANSI SQL稱爲「模式」 - 如果您的數據庫真的是模式,那麼SQL可以完成繁重的工作。 – pilcrow

+0

同樣的服務器不同的用戶和不同的數據庫,但我需要使用DBI,因爲我們在這裏駱駝的covent。我最近設置了一個觸發器,幾乎被燒死...... – MattSizzle

回答

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 = '開始' 和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中刪除行也可以通過連接來完成。多表連接只刪除DELETEFROM之間列出的表別名中的行。再次,我們使用別名「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」),其中狀態= '開始' 哪裏有匹配的行存在於T2。

+0

@Micheal你用你的答案提出了一些非常好的觀點。我需要運行一些測試,但最初看起來很穩固。希望DBA能夠迴應,因爲你們總是擁有最好的東西。再次感謝隊友。 – MattSizzle

+0

測試是好的 - 不要相信我的答案在你的現場系統上。 :)但是,如果我理解你的要求,並沒有轉換太多的表名,這應該讓你關閉。 –