在SQL Server上使用PDO时,为什么不能按列别名进行排序?

时间:2013-07-14 22:15:36

标签: php sql sql-server pdo prepared-statement

注意:以下示例中唯一的区别是 ORDER BY 子句。

好代码:

$sql = 'SELECT [date], ? AS [name] 
FROM [transactions] 
WHERE [category_id] = 10 
GROUP BY [date] 
ORDER BY [date] ASC';

$stmt = $db->prepare($sql);
$stmt->bindValue(1, 'Test', PDO::PARAM_STR);
$stmt->execute();
$data = $stmt->fetchAll();
//returns rows in $data

错误代码:

$sql = 'SELECT [date], ? AS [name] 
FROM [transactions] 
WHERE [category_id] = 10 
GROUP BY [date] 
ORDER BY [date] ASC, [name] ASC';

$stmt = $db->prepare($sql);
$stmt->bindValue(1, 'Test', PDO::PARAM_STR);
$stmt->execute();
$data = $stmt->fetchAll();
//returns an empty array

为什么我的第二个代码块不起作用?如果我直接运行此查询的任一版本(在SQL Management Studio中),它都可以正常工作。如果我摆脱PHP中的问号并将值硬编码到查询中(而不是绑定它),那也是有效的!这是怎么回事?

更新:以下示例PHP示例更好地说明了问题:http://snipt.org/ALhd1。在这个链接的示例代码中,我包含了5个“测试”。测试#1,2和4都返回结果,而测试#3和5则没有并且应该说明问题。

2 个答案:

答案 0 :(得分:1)

我已经设法用PHP 5.4和SQL Server 2012重现了这个问题。

问题似乎在于PDO的ODBC驱动程序。成功的测试使用两个驱动程序给出相同的结果,但下面使用test3作为样本。

使用Microsoft(3.0)的本机SQL Server PHP驱动程序可以得到正确的结果;

$db = new PDO('sqlsrv:server=.\\SQLEXPRESS');

array(3) { [0]=> string(5) "00000" [1]=> NULL [2]=> NULL }
array(1) { [0]=> array(4) {
    ["date"]=> string(23) "2013-07-23 10:34:24.497"
    [0]=>      string(23) "2013-07-23 10:34:24.497"
    ["name"]=> string(4) "Test"
    [1]=>      string(4) "Test"
  }
}

...使用ODBC运行完全相同的代码时会得到确切的失败结果;

$db = new PDO('odbc:driver={SQL Server Native Client 11.0};server=.\SQLEXPRESS;Trusted_Connection=yes');

array(4) { [0]=>string(5) "00000" [1]=> int(0)  
           [2]=> string(24) " ((null)[0] at (null):0)" [3]=> string(0) "" }
array(0) { }

换句话说,它不是PDO本身或SQL Server中的限制,它是ODBC驱动程序中的限制/错误。

答案 1 :(得分:0)

我试图重现这个问题,但我不能。但是,我怀疑“准备”是在order by中识别一个常数,这是一个错误。您可以使用显式常量轻松查看错误:

select *
from information_schema.tables t
order by 'a'

失败并显示错误:

Msg 408, Level 16, State 1, Line 3
A constant expression was encountered in the ORDER BY list, position 1.

那说,这有效:

select *, 'a' as name
from information_schema.tables t
order by name;

以下是解决问题的建议。尝试使用子查询:

SELECT [date], (select ?) AS [name] 
FROM [transactions] 
WHERE [category_id] = 10 
GROUP BY [date] 
ORDER BY [date] ASC, [name] ASC;

select的附加级别应该说服某些东西,某个地方你的值不是常数(并且仍然为它分配一个值)。