2016-08-30 6 views
1

RedHatボックスでPerl、DBIおよびODBCドライバを実行しています。私は、非常に最近の姉妹の質問から、ODBC接続が機能していることを知っています。クエリの最初のbind_paramに問題があります。私は、エラーを与えています:Perl、DBI MS SQL:不明なプレースホルダをバインドできません。

Can't bind unknown placeholder '1' at ./script.pl line 361. 

コードのその部分は次のようになります。

326: sub isStaff { 
327:  my ($MSdbh, $PersonLoginID, $start, $end) = @_; 
328: 
329:  my $sth = undef; 
330: 
331:  my $result = undef; 
332: 
333:  my $tmp = <<EOF; 
334: SELECT 
335:   P.PersonLoginID 
336: FROM 
337:   Personnel.Persons AS P 
338:   INNER JOIN Personnel.Memberships AS M ON M.PersonId = P.PersonId 
339:   INNER JOIN Personnel.Groups AS G ON G.GroupId = M.GroupId 
340: WHERE 
341:  UPPER(P.PersonLoginID) = UPPER('?') 
342:   AND (G.GroupAbbv = 'MyGroup' 
343:     OR G.GroupAbbv = 'SubGroup1' 
344:     OR G.GroupAbbv = 'SubGroup2') 
345:   AND (M.StartDate <= '?' 
346:     OR M.StartDate BETWEEN '?' AND '?') 
347:   AND (M.EndDate >= '?' 
348:     OR M.EndDate IS NULL) 
349: EOF 
350: 
351: $MSdbh->trace(2); 
352: 
353:  if (!($sth = $MSdbh->prepare($tmp))) { 
354:     die "DB prepare failed"; 
355:   } 
356: 
357:  print STDERR "$PersonLoginID\n"; 
358:  print STDERR "$start\n"; 
359:  print STDERR "$end\n"; 
360: 
361:   $sth->bind_param(1, $PersonLoginID, SQL_VARCHAR) 
362:     || die "bind_param 1:" . $sth->errstr; 
363:   $sth->bind_param(2, $start, SQL_DATETIME) 
364:     || die "bind_param 2:" . $sth->errstr; 
365:   $sth->bind_param(3, $start, SQL_DATETIME) 
366:     || die "bind_param 3:" . $sth->errstr; 
367:   $sth->bind_param(4, $end, SQL_DATETIME) 
368:     || die "bind_param 4:" . $sth->errstr; 
369:   $sth->bind_param(5, $end, SQL_DATETIME) 
370:     || die "bind_param 5:" . $sth->errstr; 
371: 
372:   if (!($sth->execute())) { 
373:     die "DB execute failed"; 
374:   } 
375: 
376:   $sth->bind_col(1, \$PersonLoginID) 
377:     || die "bind_columns:" . $sth->errstr; 
378: 
379:  my $i = 0; 
380:  for ($i = 0; $sth->fetch; $i++) { 
381:   ; 
382:  } 
383: 
384:  $sth->finish; 
385: 
386:  if ($i == 1) { 
387:   return 1; 
388:  } else { 
389:   return 0; 
390:  } 
391: } 

DBI->trace()と診断印刷出力は次のとおりです。

DBI::db=HASH(0x35c5420) trace level set to 0x0/2 (DBI @ 0x0/0) in DBI 1.634-ithread (pid 5792) 
    -> prepare for DBD::ODBC::db (DBI::db=HASH(0x35c54c8)~0x35c5420 'SELECT 
     P.PersonLoginID 
FROM 
     Personnel.Persons AS P 
     INNER JOIN Personnel.Memberships AS M ON M.PersonId = P.PersonId 
     INNER JOIN Personnel.Groups AS G ON G.GroupId = M.GroupId 
WHERE 
    UPPER(P.PersonLoginID) = UPPER('?') 
     AND (G.GroupAbbv = 'MyGroup' 
       OR G.GroupAbbv = 'SubGroup1' 
       OR G.GroupAbbv = 'SubGroup2') 
     AND (M.StartDate <= '?' 
       OR M.StartDate BETWEEN '?' AND '?') 
     AND (M.EndDate >= '?' 
       OR M.EndDate IS NULL) 
') thr#299a010 
    <- prepare= (DBI::st=HASH(0x3641e08)) [1 items] at billing.cgi line 353 
SomeLoginID 
2016-03-10 13:54:44 
2016-03-10 16:11:05 
    -> bind_param for DBD::ODBC::st (DBI::st=HASH(0x3641e08)~0x3641d78 1 'SomeLoginID' 12) thr#299a010 
    -> DESTROY for DBD::ODBC::st (DBI::st=HASH(0x3641d78)~INNER) thr#299a010 
    <- DESTROY= (undef) [1 items] at billing.cgi line 361 

診断プリントがその値を表示しますになるはずです。

357:  print STDERR "$PersonLoginID\n"; --> SomeLoginID 
358:  print STDERR "$start\n";   --> 2016-03-10 13:54:44 
359:  print STDERR "$end\n";   --> 2016-03-10 16:11:05 

私は最後の時間かそこら中で読んだことがあるいくつかのDBIドキュメントは?は唯一の「ポータブル」プレースホルダであることを述べています。 MS SQLは他のものを好むのですか?

文字列のプレースホルダでプレースホルダ文字の前後に一重引用符を使用しない例がありますが、それは私にとってはうまくいきませんでした。

アイデア?

+2

無関係であるはずですが、あなたの前の質問には、あなたがRAISEERRORを有効にしていることを示しました。つまり、各DBIコマンドの後に 'die 'ステートメントをすべて削除することができます。何か問題が生じた場合、自動的に例外が発生します。 – ThisSuitIsBlackNot

+0

うん、あなたは絶対に正しいです。しかし、それはレガシーコードであり、ボートがあまりにも多く揺れていないようにしたい。 –

答えて

3

char/string型の場合でもプレースホルダを引用しないでください。

... 
WHERE 
    UPPER(P.PersonLoginID) = UPPER('?') 
... 

はちょうど

... 
WHERE 
    UPPER(P.PersonLoginID) = UPPER(?) 
... 
+0

hmm、コメントが短すぎます...あなたの提案を試してみてください。最小トレース出力とエラーは次のとおりです。 DBD :: ODBC :: st bind_paramが失敗しました:[unixODBC] [FreeTDS] [SQL Server] ./script.pl行363のデータ型が無効です(SQL-HY004)。 SQL-HY004では、日付フィールドにSQL_DATETIMEの代わりにSQL_TIMESTAMPを使用するように指示しました。それは私をもっと遠くまで運んできました。今は他の問題がありますが、おそらく管理可能です。 ありがとう –

関連する問題