PHP ODBC不接受带有空格的列名的别名

时间:2012-08-30 15:11:05

标签: php sql sql-server odbc

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

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

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

Anywho,我之前通过将他们的名字放在方括号中来访问这些列,例如[列名],它在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(无论如何)AS'别名'这样的工作正常...只是没有选择列作为别名......? :/

4 个答案:

答案 0 :(得分:3)

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

+''
列名,但在AS别名之前,您应该能够绕过此问题。

答案 1 :(得分:1)

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

看来,声明至少一个变量(无论是否正在使用它)将防止此特定错误的发生。该变量可以是任何类型。

如果您只执行 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;

现在,如果您在存储过程中遇到了此问题,则可以通过在正文中的任何地方定义变量,采用与上述相同的方法。

我注意到的另一件事是,如果存储过程是使用参数定义的,则如果您的参数得到了 set 设置或在诸如 if语句之类的值中进行了评估,则此错误也不会发生。例如,

// 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

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

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

答案 2 :(得分:1)

面对类似的问题。在我的情况下,odbc_connect的第四个参数选择了游标类型 SQL_CUR_USE_ODBC

答案 3 :(得分:0)

实际上,@ dearsina的方法似乎是处理这个bug的一种观察方式。

但是,此解决方案不适用于所有数据类型。所以对我来说,覆盖所有所需列的唯一方法是CAST()相关列(最初c.State的数据类型为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)