虽然这个问题引用了PHP,但实际上并不是特定于PHP的,所以我没有将其标记为。
我们有一个支持多个数据库后端的PHP框架。
我们的数据对象类中有一个泛型函数,它允许您使用指定的条件和排序顺序从基础表中获取记录。
它看起来像这样:
function GetAll($Criteria, $OrderBy = "") {
...
// Add primary key (column 1) to end of order by list,
// so that returned order is predictable.
if ($OrderBy != "") {
$OrderBy .= ", ";
}
$OrderBy .= "1";
...
// Build and run query, returning the result as an array.
}
如果在$OrderBy
对象上指定StaffID
参数Staff
,则生成的SQL类似于以下内容:
SELECT * FROM adminStaff ORDER BY StaffID, 1;
这在MySQL后端工作正常,从我搜索网络到大多数其他数据库后端也应该没问题。但是,使用SQL Server时,我们收到以下错误消息:
A column has been specified more than once in the order by list.
Columns in the order by list must be unique.
这是因为SQL Server不允许在ORDER BY子句中多次出现相同的列。在这种情况下,StaffID
是第1列,因此我们有同一列的多个实例。
有没有办法在SQL Server中禁用此检查? MySQL提供了很多选项来启用/禁用严格性检查和不兼容的功能 - SQL Server是否提供了允许上述查询无错运行的任何性质?
如果没有,您对我们如何在数据对象层中解决此问题有任何建议吗?请记住,我们需要保持与期望此行为的现有项目的兼容性,因此仅在$OrderBy
为空时包含第一列是不够的。
由于字段列表可以在数据对象配置的其他位置自定义,因此情况也略微复杂,因此我们不能依赖*
作为字段列表 - 它可能包含漂亮在普通的SQL字段列表中有效的任何内容。但是,如果这个问题太多,那么简单案例(如上所述)的解决方案将是一个良好的开端!
答案 0 :(得分:1)
在SQL Server中,您可以按列名称或SELECT列表中列顺序的顺序位置进行排序。
在您的情况下,列StaffID
成为序号位置1
。因此,SQL Server无法对基于同一列的相同结果集进行两次排序。
如果从查询中删除1
,则问题将得到解决。
避免使用列的序号位置进行排序。
答案 1 :(得分:1)
我在框架层面提出了几个潜在的解决方案。所有这些都具有性能影响,需要进行分析,并且在实践中可能会将其中的部分或全部排除在外。但是,至少在理论上,这些是可以实现通用解决方案的方法。
*
或table.*
则需要架构查找。如果我们需要组合处理表别名和通配符,可能会太困难。答案 2 :(得分:0)
你能否追加' - '使用SQL Server时的OrderBy参数,并在必要时显式定义Order By字段?
答案 3 :(得分:0)
基本问题 - 是否可以抑制对ORDER BY列重复的SQL Server限制 - Venu回答:不,不是。
关于如何以通用方式编码此限制,有各种建议(主要来自我)。对于任何未来的读者,如果您正在调整现有系统,那些答案可能是最有帮助的。 (如果您是从头开始,请尽量避免这种情况。)
但是,我遇到的实际解决方案是为我们的DBAL的内部API添加版本控制。 API版本现在为2
,但您可以调用setApiVersion(1)
来指示后端使用旧版本的API。
v2与v1 *相同,除非它不再自动将第1列添加到ORDER BY,除非它完全为空。因此,SQL Server问题已针对新(v2)项目解决,而现有项目可以设置为使用v1 API,因此可以继续正常工作(但没有SQL Server兼容性)。
(*实际上,我借此机会在v2中进行了一些其他重大更改,但这与此答案无关。)