【问题标题】:PHP ODBC not accepting alias on column name with spacePHP ODBC不接受带空格的列名别名
【发布时间】:2012-08-25 08:52:55
【问题描述】:

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

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

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

任何人,我以前一直通过将它们的名称放在方括号中来访问这些列,例如[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' 之类的操作,并且效果很好...只是不选择列作为别名...? :/

【问题讨论】:

  • 省略 AS 关键字并使用 [assessment name] AssessmentName 有什么区别?
  • 不,刚刚试过。尝试不带引号和带引号(别名)没有区别。可能是 ODBC 驱动程序的问题吗?这是我在谷歌上搜索的唯一建议,但没有关于如何实际解决它。
  • 只是猜测,你试过用反引号代替方括号吗?
  • 您好,Microsoft SQL 不接受反引号作为有效语法。
  • 我刚试过select "atext" from table_1,其中atext 是列名,它接受引号,这可能值得一试。

标签: php sql sql-server odbc


【解决方案1】:

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

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

【讨论】:

  • 这解决了我的问题。但是,是的,正确的方法是什么?
【解决方案2】:

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

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

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

否则您可能会收到类似于

的错误消息

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

参考CASTing 大型数据集: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)

【讨论】:

    【解决方案3】:

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

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

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

    现在,如果您的存储过程遇到了这个问题,您可以通过在主体中定义一个变量anywhere来采用上述相同的方法。

    我注意到的另一件事是,如果存储过程是用参数定义的,如果你的参数被 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
    

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

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

    【讨论】:

      【解决方案4】:

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

      【讨论】:

        猜你喜欢
        • 2015-08-25
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2016-10-28
        相关资源
        最近更新 更多