【问题标题】:Invalid cursor state, SQL state 24000 in SQLExecDirect游标状态无效,SQLExecDirect 中的 SQL 状态 24000
【发布时间】:2009-11-17 23:13:07
【问题描述】:

我需要在PHP中通过ODBC依次调用两个存储过程:

#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,在调用之间重置光标位置?有点不合我意。

【问题讨论】:

    标签: php sql-server stored-procedures odbc database-cursor


    【解决方案1】:

    尝试让人们使用 SQL Server 获得无效游标状态的方法:

    SET NOCOUNT ON;
    

    在存储过程或 SQL 脚本的顶部。 在这里找到:https://social.msdn.microsoft.com/Forums/en-US/f872382a-b226-4186-83c7-0d0fcadcd3eb/invalid-cursor-state?forum=sqldataaccess 我在 SQL Server 2017 中运行一些非常普通的 SQL 时遇到了这个问题

    【讨论】:

      【解决方案2】:

      打开数据库的两个句柄。 ODBC 可能会在句柄中维护光标。

      【讨论】:

      • 同时打开两个并为每个使用一个不起作用。但是关闭连接并在查询之间创建一个新的连接确实如此。这不是一个理想的答案,我仍在四处寻找。我的本地安装使用不同的 ODBC 驱动程序,可以按顺序运行这两个驱动程序。所以也许那里有什么……
      • 好吧,进一步的研究并没有让我有所收获。所以我正在关闭并重新打开每个连接的数据库。似乎是一项昂贵的操作,但至少我正在做的事情不需要最高性能。
      【解决方案3】:

      我遇到了同样的问题,但是在两个查询之间的 odbc_free_result($result) 为我完成了这项工作。

      Documentation:

      bool odbc_free_result ( resource $result_id )

      与结果相关的免费资源。

      odbc_free_result()只有在担心的时候才需要调用 脚本运行时使用过多内存。所有结果记忆 脚本完成后会自动释放。

      注意: 如果自动提交被禁用(参见odbc_autocommit())并且您之前调用了odbc_free_result() 提交时,所有待处理的事务都会回滚。

      【讨论】:

      • 提供一些更合适的细节。
      【解决方案4】:

      我也发现了确切的问题。显然这在免费的 ODBC 驱动程序中很常见。这是我早上尝试将项目从 MySQL 迁移到 ODBC SQL Server 时的头疼问题。我终于找到了解决这个问题的方法。

      显示此错误是因为上一个结果集中仍然存在活动游标。通过确保在发布新记录集之前通读整个第一个记录集(即使只使用其中的一部分),我能够在不使用断开/重新连接方法的情况下摆脱此错误。注意:我使用的是 PHP。

      给我一个错误:

      $sql="SELECT COUNT(whatever) as whatever FROM whatever";<br />
      $countResult = odbc_exec($db, $sql);<br />
      $countMenuHeader = odbc_fetch_array($countResult);<br />
      extract ($countMenuHeader);<br />
      $countRecords = $NumMenuHeader;<br />
      
      $sql="SELECT whatever as whatever FROM whatever";<br />
      $result = odbc_exec($db, $sql);<br />
      $MenuHeader = odbc_fetch_array($result);<br />
      

      清除错误:

       $sql="SELECT COUNT(whatever) as whatever FROM whatever";<br />
       $countResult = odbc_exec($db, $sql);<br />
      
       while($countMenuHeader = odbc_fetch_array($countResult))<br />
       {<br />&nbsp;&nbsp;
       extract ($countMenuHeader);<br />&nbsp;&nbsp;
       $countRecords = $NumMenuHeader;<br />}
      
       $sql="SELECT whatever as whatever FROM whatever";<br />
       $result = odbc_exec($db, $sql);<br />
       $MenuHeader = odbc_fetch_array($result);<br />
      

      简而言之,确保在移动到 下一个语句。

      【讨论】:

        【解决方案5】:

        尝试使用不同的游标访问结果,$result1 和 $result2。

        【讨论】:

        • 没有什么不同。不过还是谢谢。
        【解决方案6】:

        只是为了澄清调用 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(),否则我可能会收到“Invalid cursor state.SQLSTATE=24000”错误消息。

        这是因为我们必须确保在移动到下一条语句之前完全读取或获取所有数据集。$sth->finish() 向 DBI 指示您已完成 语句句柄。然后可以重用它来调用 execute()

        我还发现我可以将 fetch 放在 while 循环中,即使只返回了一行但查询。似乎试图获取下一个不存在的行也会使某事可以重新执行。

        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"))
            {
                 ...
            }    
        }
        

        这两种解决方案都对我有用。 :)

        【讨论】:

          【解决方案7】:

          在 PHP 中使用 unixODBC 和 freeTDS 打开嵌套查询的解决方法

          如果您可以修改您的 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 条目。 它不是很漂亮,但它对我有用,直到有多个光标可用。

          【讨论】:

            猜你喜欢
            • 2011-04-13
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2016-11-19
            • 2014-12-11
            相关资源
            最近更新 更多