web-dev-qa-db-ja.com

MSSQLでPDOを使用した「アクティブな結果にフィールドが含まれていません」

いくつかの古いPHPページをPDOを使用するように変換しています。

以下は、私が抱えている問題の理解を助けるための2つの簡略化されたクエリ(実際のクエリではありません)です...

SELECT afield INTO #temptable FROM atable WHERE anotherfield = 'somevalue';

SELECT afield,anotherfield,onemorefield FROM atable 
WHERE afield NOT IN (SELECT * FROM #temptable);

上記のクエリは、タイトルで説明されているエラーをスローします(より完全に「致命的なエラー:メッセージ 'SQLSTATE [IMSSP]:クエリのアクティブな結果にフィールドが含まれていません。

このようにクエリを変更すると...

with (SELECT afield INTO #temptable FROM atable 
WHERE anotherfield = 'somevalue') AS temptable;

SELECT afield,anotherfield,onemorefield FROM atable 
where afield NOT IN (SELECT * FROM temptable);

これはエラーを回避するように見えますが、このバージョンのクエリは、他のクエリのすべてのフィールド比較に対して魅力的なクエリを実行しているように見えるため、恐ろしくひどく非効率的です。

最初のフォーム(一時テーブルを1回作成する)をPDOで機能させる方法はありますか?

Mssqlを使用していた古いページでは正常に機能しました。

EDIT:実際のテーブルを作成し、phpで実行し、2番目のクエリを(別のphp呼び出しで)実行してから、3番目を実行することで、おそらくこれを「厄介な」方法で実行できることを知っています最初のテーブルを削除するクエリ。しかし、私はむしろそれに頼る必要はありません! :)

16
MrVimes

ストアドプロシージャを使用している場合は、

SET NOCOUNT ON 

問題は、ストアドプロシージャが最初の結果として影響を受けた行数を含む結果を返すことです。

Microsoftドキュメント

51
user3228005

PDOエンジンは、このクエリを2つの結果セットを返すものと見なします(古いmssqlエンジンは、クエリ文字列全体の最後のクエリを除くすべてを無視した可能性があります)。次のコマンドを使用して、最初の結果セット(一時テーブル)をスキップすることでうまく機能させました

_$statement->nextRowset();
_

そして、通常どおり$statement->fetch();を使用します

14
MrVimes

私はこの問題に遭遇し、上記の回答が役に立ちましたが、ここでの回答は次のことを前提としています。

  1. _SET NOCOUNT ON_でsprocを変更するためのアクセス権があり、これを実行したい
  2. 次の行セットに移動する必要があることは確かです$statement->nextRowset();

私の場合、一般的な方法を使用して複数のsprocからデータをプルバックしていますが、この問題がある場合とない場合があり、行セットをインクリメントする前に確認する必要があります。

私は以下を使用しました:

_while($stmt->columnCount() === 0 && $stmt->nextRowset()) {
    // Advance rowset until we get to a rowset with data
}

if($stmt->columnCount() > 0) {
    // We found something with data, do stuff.
    // Code here
}
_

うまくいけば、これは他の誰かが同様の問題に遭遇するのを助けるでしょう。

5
Bryan