讓我們有一個表:DBD :: SQLite,如何通過佔位符在查詢中傳遞數組?
sqlite> create table foo (foo int, bar int);
sqlite> insert into foo (foo, bar) values (1,1);
sqlite> insert into foo (foo, bar) values (1,2);
sqlite> insert into foo (foo, bar) values (1,3);
然後選擇一些數據:
sqlite> select * from foo where foo = 1 and bar in (1,2,3);
1|1
1|2
1|3
工作的很好。現在我試圖使用DBD :: SQLite 1.29:
my $sth = $dbh->prepare('select * from foo where foo = $1 and bar in ($2)');
$sth->execute(1,[1,2,3]);
並且這給了我空結果。 DBI跟蹤顯示第二個佔位符綁定到數組,但沒有分數。如果我在一個字符串中的數組值並傳遞它,沒有結果。如果我壓扁數組,我會得到「用N個佔位符而不是2來調用」的可預測錯誤。
我有點不知所措。還有什麼要嘗試?
Upd:好的,下面是真實世界應用程序中的一個真實示例。
首先,設置:我有幾個表格填充統計數據,列數從10到700+不等。我正在討論的查詢選擇該數據的子集用於報告目的。不同的報告考慮不同的方面,因此運行不同的查詢,每個請求一個或多個。有200多個報告,即200-300個查詢。這種方法是爲Postgres開發的,現在我需要縮小它並使其與SQLite一起工作。考慮到所有這些與Postgres的配合良好,我無法證明我們可以通過查詢並重寫它們。維修不好。我可以並且確實使用就地查詢調整,例如用IN()替換= ANY(),這些都是次要方面。
所以,這裏是我的榜樣:2個查詢連續跑了一個報告:
SELECT SPLIT, syn(SPLIT),
(SELECT COUNT(*) FROM cagent WHERE ACD = $1 AND SPLIT = $2 AND
LOC_ID = ANY ($3) AND LOGID IS NOT NULL AND WORKMODE = 40),
(SELECT COUNT(*) FROM cagent WHERE ACD = $1 AND SPLIT = $2 AND
LOC_ID = ANY ($3) AND LOGID IS NOT NULL AND WORKMODE = 30),
(SELECT COUNT(*) FROM cagent WHERE ACD = $1 AND SPLIT = $2 AND
LOC_ID = ANY ($3) AND LOGID IS NOT NULL AND WORKMODE = 50),
(SELECT COUNT(*) FROM cagent WHERE ACD = $1 AND SPLIT = $2 AND
LOC_ID = ANY ($3) AND LOGID IS NOT NULL AND WORKMODE = 220),
(SELECT COUNT(*) FROM cagent WHERE ACD = $1 AND SPLIT = $2 AND
LOC_ID = ANY ($3) AND LOGID IS NOT NULL),
(SELECT COUNT(*) FROM cagent WHERE ACD = $1 AND SPLIT = $2 AND
LOC_ID = ANY ($3) AND LOGID IS NOT NULL AND WORKMODE = 20),
(SELECT COUNT(*) FROM cagent WHERE ACD = $1 AND SPLIT = $2 AND
LOC_ID = ANY ($3) AND LOGID IS NOT NULL AND WORKMODE = 80)
FROM csplit WHERE ACD = $1 AND SPLIT = $2
SELECT syn(LOGID), syn(LOC_ID), LOGID, EXTENSION, syn(ROLE), PERCENT,
syn(AUXREASON), syn(AWORKMODE), syn(DIRECTION), WORKSKILL, syn(WORKSKLEVEL),
AGTIME FROM cagent WHERE ACD = $1 AND SPLIT = $2 AND LOC_ID = ANY ($3) AND
LOGID IS NOT NULL
這還不是最複雜的例子,因爲可以有任意數量的使用的輸入參數,在不同的地方重複使用查詢;將其替換爲通用的?
佔位符並不是一項簡單的任務。對Postgres運行查詢的代碼如下所示(輸入清理後):
sub run_select {
my ($class, $dbh, $sql, @bind_values) = @_;
my $sth;
eval {
$sth = $dbh->prepare_cached($sql);
$sth->execute(@bind_values);
};
[email protected] and die "Error executing query: [email protected]";
my %types;
{
my $dbt = $dbh->type_info_all;
@types{ map { $_->[1] } @$dbt[1..$#$dbt] } =
map { $_->[0] } @$dbt[1..$#$dbt];
};
my @result;
while (my $row = $sth->fetchrow_arrayref) {
my $i = 0;
push @result, [ map { [ $types{${$sth->{TYPE}}[$i++]}, $_ ] } @$row ];
};
return \@result;
};
我可以重寫查詢並直接注入值; SQL注入並不是太大的威脅,因爲所有的輸入在命中SQL引擎之前很久都沒有被正則表達式模仿。我不想動態地重寫查詢,原因有兩個:a)它可能會導致價值引用問題,並且b)它會殺死prepare_cached背後的全部原因。如果每次更改準備好的語句,SQL引擎都不能緩存它。
現在正如我所說的,上面的代碼與Postgres很好地協作。由於SQLite引擎本身顯然有可能使用數據集,所以我認爲這是DBD :: SQLite實現的一個缺陷。所以真正的問題聽起來像:有沒有辦法通過DBD :: SQLite在佔位符中傳遞數據集?不一定數組,儘管這是最合乎邏輯的。
也許你應該發佈一個wha的實例,而不是張貼編寫的代碼t您從應用程序/庫中獲取的數據。 – MkV 2011-04-09 20:49:18
-1這個問題的質量很差 – 2013-09-13 12:45:34