2014-03-27 39 views
7

假設我查詢表像下面這樣:可以DBI推斷或獲取數據列類型時獲取行?

$dbh->selectrow_hashref('SELECT id, name FROM foos WHERE name = "bar"'); 

當然,id將是一個整數,但由此產生的hashref將內部存儲爲一個Perl PV,而不是一個IV值。這反過來會在將數據序列化到例如JSON時產生不希望的結果。

當然,人們可以手動調用0+的值,但有沒有辦法讓DBI自動將它存儲爲一個實際的整數,而不僅僅是一個看起來像數字的字符串?也承認DBIx::Class和朋友有解決這個問題的方法,但是DBI由它的寂寞?

回答

7

根據您的數據庫驅動程序,您可能*能夠使用類型提示在bind_col

use DBI qw(:sql_types); 

... 

my $sth = $dbh->prepare('SELECT id, name FROM foos WHERE name = "bar"'); 
$sth->execute; 

$sth->bind_col(1, undef, { 
    TYPE => SQL_INTEGER, 
    StrictlyTyped => 1, 
    DiscardString => 1 
}); 

while (my $hr = $sth->fetchrow_hashref) { 
    say to_json $hr; 
} 

這嘗試的第一列(從一個索引)綁定到SQL_INTEGER類型和如果轉換失敗,則拋出錯誤。如bohica notesDiscardString屬性是必需的,因爲它「拋棄了數據的字符串部分(pv)」。


*按照DBI文檔:

幾個驅動支持指定通過bind_col呼叫的數據類型(大多數人會簡單地忽略數據類型)。

DBD::OracleDBD::ODBC支持它,並且DBD::Pg可以支持它,根據this thread(雖然我無法驗證的話),而DBD::mysql沒有。我不確定其他車手。

+0

+1很好的答案。 – friedo

6

雖然ThisSuitlsBlackNot幾乎是正確的,但他的答案有一些重要的遺漏。作爲大多數StrictlyTyped和DiscardString屬性的作者,我可以告訴你,實際上,在這種情況下DiscardString屬性更重要。

DBI將嘗試將您的數據轉換爲指定的類型,如果失敗,您的數據將被單獨保留並且不會生成錯誤。如果轉換失敗並指定了StrictlyTyped,則會生成錯誤。

DiscardString屬性拋棄數據的字符串部分(pv)將被丟棄。當使用JSON :: XS和其他JSON模塊時,這尤其重要,因爲JSON :: XS專門查看PV。

所以真的,你應該至少做:

$sth->bind_col(1, undef, {TYPE => SQL_INTEGER, DiscardString => 1}); 

注數的DBD居然不搭理在bind_col綁定類型。 DBD :: ODBC確實是因爲我維護它。 DBD :: Oracle通常不會關注TYPE,除非與StrictlyTyped和/或DiscardString一起使用(因爲我已經爲完全相同的問題添加了該功能)。

無論是駕駛員通過搜索使用的sql_type_cast代碼支持這些屬性或不僅能真正被確定(除非文檔是這麼說的),以及它們的XS等同sql_type_cast_svpv等我不相信DBD :: PG支持StrictlyTyped或DiscardString;實際上我相信在這個時候只有DBD :: ODBC和DBD :: Oracle(正如我添加它們那樣)。

您可能還會發現this有趣。

+0

感謝您填寫我錯過的內容。 – ThisSuitIsBlackNot