Недопустимое состояние курсора, состояние SQL 24000 в SQLExecDirect - PullRequest
4 голосов
/ 18 ноября 2009

Мне нужно вызвать две хранимые процедуры последовательно через ODBC в PHP:

#run stored procedure 1
$query = "Shipped_Not_Shipped_Rep ".$_GET['rep_id'];
$result = odbc_exec($dbh, $query);
odbc_result_all($result);

#run stored procedure 2
$query = "Shipped_Not_Shipped_Account ".$_GET['account_id'];
$result = odbc_exec($dbh, $query);
odbc_result_all($result);

Я получаю эту ошибку в PHP после второго вызова хранимой процедуры:

Предупреждение: odbc_exec () [function.odbc-exec]: ошибка SQL: [unixODBC] [FreeTDS] [SQL Server] Неверно состояние курсора, состояние SQL 24000 в SQLExecDirect

Если я переставляю порядок, который я называю хранимыми процедурами, это всегда вторая ошибка. Есть ли способ, idk, сбросить положение курсора между вызовами? Немного вне моей стихии.

Ответы [ 7 ]

4 голосов
/ 18 ноября 2009

Открыть две ручки для базы данных. ODBC, вероятно, поддерживает курсор в дескрипторе.

2 голосов
/ 24 мая 2011

Я также нашел точную проблему. По-видимому, это характерно для бесплатных драйверов ODBC. Это было моей утренней головной болью от попыток перенести проект с MySQL на ODBC SQL Server. Я наконец нашел то, что избавило меня от этого.

Эта ошибка появляется, потому что активный курсор все еще существует из предыдущего набора результатов. Мне удалось избавиться от этой ошибки, не используя метод отсоединения / переподключения, убедившись, что я прочитал весь первый набор записей (даже если использовал только его частичную часть) перед выпуском новой. Примечание: я использую PHP.

выдает ошибку:

$ sql = "ВЫБЕРИТЕ СЧЕТЧИК (как угодно), как и любой другой";
$ countResult = odbc_exec ($ db, $ sql);
$ countMenuHeader = odbc_fetch_array ($ countResult);
извлечь ($ countMenuHeader);
$ countRecords = $ NumMenuHeader;

$ sql = "ВЫБЕРИТЕ что-либо как что-либо ИЗ ЧЕГО";
$ result = odbc_exec ($ db, $ sql);
$ MenuHeader = odbc_fetch_array ($ result);

Устранена ошибка:

$ sql = "ВЫБЕРИТЕ COUNT (что угодно) как что-либо ИЗ ЧЕГО";
$ countResult = odbc_exec ($ db, $ sql);

while ($ countMenuHeader = odbc_fetch_array ($ countResult))
{
извлечь ($ countMenuHeader);
$ countRecords = $ NumMenuHeader;
}

$ sql = "ВЫБЕРИТЕ что-либо как что-либо ИЗ ЧЕГО";
$ result = odbc_exec ($ db, $ sql);
$ MenuHeader = odbc_fetch_array ($ result);

Короче говоря, убедитесь, что вы полностью прочитали или получили набор данных, прежде чем перейти к следующее утверждение.

1 голос
/ 16 января 2019

Что-то, чтобы попробовать для людей, получающих недопустимое состояние курсора с сервером SQL:

SET NOCOUNT ON;

В верхней части хранимой процедуры или сценария SQL. Найдено здесь: https://social.msdn.microsoft.com/Forums/en-US/f872382a-b226-4186-83c7-0d0fcadcd3eb/invalid-cursor-state?forum=sqldataaccess У меня была эта проблема просто запустить какой-то очень средний SQL в SQL Server 2017

1 голос
/ 31 марта 2014

Я столкнулся с той же проблемой, но odbc_free_result($result) между двумя запросами сделал работу для меня.

Документация

bool odbc_free_result ( resource $result_id )

Свободные ресурсы, связанные с результатом.

odbc_free_result() нужно вызывать, только если вы беспокоитесь о используя слишком много памяти во время работы вашего скрипта. Вся память результатов будет автоматически освобожден после завершения сценария.

Примечание: Если автоматическая фиксация отключена (см. odbc_autocommit()) и вы звоните odbc_free_result() раньше При фиксации все ожидающие транзакции откатываются.

0 голосов
/ 17 апреля 2015

Обходной путь для открытия вложенных запросов с использованием unixODBC и freeTDS в PHP

если вы можете изменить свой odbc.ini, создайте другой раздел конфигурации, используя ту же информацию о соединении, но с другим именем раздела:

[DATASOURCE1]
Description = "Data Connection 1"
Driver = FreeTDS
Server = <your server>
Port = 1433
Database = <your db>

[DATASOURCE1A]
Description = "Data Connection 2"
Driver = FreeTDS	
Server = <your server>
Port = 1433
Database = <your db>

Затем в вашем коде создайте два дескриптора, по одному для каждого описания источника данных:

$dbhandle = odbc_connect('DATASOURCE1', 'user', 'password');
$dbhandle1 = odbc_connect('DATASOURCE1A', 'user', 'password');

Тогда вы можете использовать дескрипторы во вложенных запросах:

$dbresult = odbc_exec($dbhandle, "SELECT <some sql>");
while($row = odbc_fetch_array($dbresult)) {

	$dbresult1 = odbc_exec($dbhandle1, "<some different sql>");

	while($row1 = odbc_fetch_array($dbresult1)) {
		
		#do stuff with nested query data like $row['name'] and $row1['time']
	}
}

Вы можете вкладывать глубже, но вы должны создать запись odbc.ini для каждого уровня. Это не красиво, но это работает для меня, пока несколько курсоров доступны.

0 голосов
/ 24 октября 2014

Просто чтобы уточнить, что вызов метода finish () означает, что вы просто завершили текущий запрос и его результаты, и теперь вы можете безопасно снова вызвать execute (). Нет необходимости сначала вызывать prepare ().

Я поймал это в AIX, используя драйвер ODBC для базы данных DB2 SQL. Я думаю, что это была AIX, у которой был старый драйвер ODBC, возможно, потому что в Linux все было хорошо.

Во всяком случае, я выполнил запрос SQL, который снова и снова возвращает одну строку в цикле for, и получил ошибку 24000.

my $sth = $dbh->prepare( $query ) or die "dying";

foreach my $i (@blah)
{
    $sth->execute($fred, $i) or die "dying";

    my $hash_ref = $sth->fetchrow_hashref("NAME_uc"); # only a single row exists

    ...

    $sth->finish(); # MUST do this
} 

Мой вывод заключается в том, что мне пришлось вызвать $ sth-> finish (), чтобы я мог снова безопасно вызвать $ sth-> execute (), в противном случае я мог бы получить сообщение об ошибке «Недопустимое состояние курсора. SQLSTATE = 24000».

Это потому, что мы должны убедиться, что полностью прочитали или извлекли весь набор данных, прежде чем перейти к следующему оператору. $ Sth-> finish () указывает DBI, что вы закончили с дескриптор Затем его можно повторно использовать для вызова execute ()

Я также обнаружил, что вместо этого я могу поместить выборку в цикл while, хотя когда-либо возвращается только одна строка, кроме запроса. Кажется, что попытка извлечь следующую несуществующую строку также делает sth пригодным для выполнения.

my $sth = $dbh->prepare( $query ) or die "dying";

for
{ 
    $sth->execute($fred, $i) or die "dying";

    while (my $hash_ref = $sth->fetchrow_hashref("NAME_uc"))
    {
         ...
    }    
}

Оба решения работали для меня. :)

0 голосов
/ 18 ноября 2009

Попробуйте получить доступ к результатам, используя разные курсоры, $ result1 и $ result2.

...