5

基本上,我需要使用 PHP 从 SQL Server 2005 中获取一些数据。

之前我们使用了mssql_*函数,但是由于各种服务器问题,我们现在只能使用odbc_*函数。

该表有各种列,其名称中有空格,在建议之前....不,我无法更改它们,因为这是另一种语言的完全独立的软件,它会破坏它,我只是得到统计数据其中。

Anywho,我以前一直通过将它们的名称放在方括号中来访问这些列,例如 [column name] 并且它在mssql_*函数下运行良好,但是当我这样做时:

$sql = "select top 1 [assessment name] as AssessmentName from bksb_Assessments";
$result = odbc_exec($db, $sql);
while($row = odbc_fetch_array($result))
{
    var_dump($row);
}

它将结果打印为:

'评估名称' => 字符串'数学 E3 诊断'(长度 = 25)

所以你可以看到它完全忽略了我给它的别名,仍然称它为[评估名称]。

但是,如果我在 SQL Server Management Studio Express 中运行完全相同的东西,它可以正常工作并使用别名。

我尝试了各种不同的组合,例如引用别名、引用列、不同的括号等……但到目前为止还没有运气。

这不是一个大问题,因为我可以更改我的脚本用于在结果数组而不是别名中查找“评估名称”的内容,但我无法弄清楚为什么会发生这种情况,这有点烦人。 ..

干杯! :)

编辑:

实际上我不认为方括号有什么不同,只是试图通过 php odbc 对任何列进行别名处理,但是我仍然可以做类似 CAST(whatever) AS 'alias' 之类的事情,而且效果很好......只是没有选择一列作为别名......?:/

4

4 回答 4

4

这绝不是一个完美的解决方案,我很想学习处理这个问题的正确方法,但同时,添加

+''
到每一列,在基础列名之后,但在 AS 别名之前,您应该能够规避这个问题。

于 2012-10-18T17:59:53.617 回答
2

在尝试解决此问题并确定为什么我的团队的某些存储过程会出现这种行为时,我终于找到了原因。奇怪的是,我们只在几个存储过程中遇到了这个问题,而大多数都按预期返回了别名。

似乎声明至少一个变量,无论它是否被使用,都可以防止这个特定的错误发生。变量可以是任何类型。

如果您只是在不使用存储过程的情况下执行SELECT查询,请使用DECLARE语句在语句之前之后定义变量:

// This works...
DECLARE @ignore TINYINT; SELECT EmployeeID AS employee_id FROM Employee;

// So does this...
SELECT EmployeeID AS employee_id FROM Employee; DECLARE @ignore TINYINT;

现在,如果您在存储过程中遇到这个问题,您可以通过在正文中的任何位置定义一个变量来采用上述相同的方法。

我注意到的另一件事是,如果存储过程是用参数定义的,如果你的参数在if 语句中被设置或评估,这个 bug 也不会发生。例如,

// This works...
CREATE PROC get_employee(
  @employee_id VARCHAR(16) = NULL
)
AS
  IF (@employee_id IS NOT NULL)
  BEGIN
    SELECT FirstName AS first_name FROM Employee WHERE EmployeeID = @employee_id;
  END
GO

使用SET

// So does this...
CREATE PROC get_employee(
  @employee_id VARCHAR(16) = NULL,
  @ignore TINYINT
)
AS
  SET @ignore = NULL;

  SELECT FirstName AS first_name FROM Employee WHERE EmployeeID = @employee_id;
GO

我仍然不太了解错误的原因或性质;但是这些变通方法,类似于上面的类型转换技巧,似乎可以解决这个烦人的错误。

可能还值得一提的是,我们在Ubuntu 14.04PHP 5.4中没有遇到这个问题。一旦我们升级到Ubuntu 18.04PHP 7.2,我们就开始遇到这个问题。在这两种情况下,我们都将 FreeTDS 配置为使用7.1版本,这就是为什么我们对这个特定的错误感到困惑。

于 2019-04-02T22:17:56.297 回答
2

@dearsina 的方法实际上似乎是处理此错误的少数方法之一。

但是,此解决方案不适用于所有数据类型。所以对我来说,覆盖所有需要的列的唯一方法是CAST()相关列(最初 c.State 将是 datatype bit):

SELECT
    CAST(c.State AS nvarchar) AS 'customer_state'
FROM
    customers AS c;

否则您可能会收到类似于

数据类型 bit 和 varchar 在 add 运算符中不兼容。

CAST大型数据集参考: https ://social.msdn.microsoft.com/Forums/sqlserver/en-US/643b6eda-fa03-4ad3-85a1-051f02097c7f/how-much-do-cast-statements-affect-performance ?forum=transactsql


关于这个主题的一些进一步发现是最近(2017 年 11 月)在 bugs.php.net 上提出的错误报告,声称该问题与 FreeTDS 有关:https ://bugs.php.net/bug.php?id=75534 。此错误报告包含一个非官方的(至少从我的最终未经测试的)补丁

diff --git a/ext/odbc/php_odbc_includes.h b/ext/odbc/php_odbc_includes.h
index 93e2c96..8451bcd 100644
--- a/ext/odbc/php_odbc_includes.h
+++ b/ext/odbc/php_odbc_includes.h
@@ -292,18 +292,16 @@ void odbc_sql_error(ODBC_SQL_ERROR_PARAMS);

 #define PHP_ODBC_SQLCOLATTRIBUTE SQLColAttribute
 #define PHP_ODBC_SQLALLOCSTMT(hdbc, phstmt) SQLAllocHandle(SQL_HANDLE_STMT, hdbc, phstmt)
-
-#define PHP_ODBC_SQL_DESC_NAME SQL_DESC_NAME
 #else
 #define IS_SQL_LONG(x) (x == SQL_LONGVARBINARY || x == SQL_LONGVARCHAR)

 #define PHP_ODBC_SQLCOLATTRIBUTE SQLColAttributes
 #define PHP_ODBC_SQLALLOCSTMT SQLAllocStmt
-
-#define PHP_ODBC_SQL_DESC_NAME SQL_COLUMN_NAME
 #endif
 #define IS_SQL_BINARY(x) (x == SQL_BINARY || x == SQL_VARBINARY || x == SQL_LONGVARBINARY)

+#define PHP_ODBC_SQL_DESC_NAME SQL_DESC_LABEL
+
 PHP_ODBC_API ZEND_EXTERN_MODULE_GLOBALS(odbc)
 #define ODBCG(v) ZEND_MODULE_GLOBALS_ACCESSOR(odbc, v)
于 2018-01-16T12:07:39.803 回答
1

面临类似的问题。odbc_connect的第四个参数在我选择游标类型SQL_CUR_USE_ODBC的情况下起到了作用。

于 2020-06-05T17:54:13.057 回答