如何避免重复列

时间:2017-03-13 14:32:38

标签: sql-server portability

虽然这个问题引用了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字段列表中有效的任何内容。但是,如果这个问题太多,那么简单案例(如上所述)的解决方案将是一个良好的开端!

4 个答案:

答案 0 :(得分:1)

在SQL Server中,您可以按列名称或SELECT列表中列顺序的顺序位置进行排序。

在您的情况下,列StaffID成为序号位置1。因此,SQL Server无法对基于同一列的相同结果集进行两次排序。

如果从查询中删除1,则问题将得到解决。

避免使用列的序号位置进行排序。

答案 1 :(得分:1)

我在框架层面提出了几个潜在的解决方案。所有这些都具有性能影响,需要进行分析,并且在实践中可能会将其中的部分或全部排除在外。但是,至少在理论上,这些是可以实现通用解决方案的方法。

  1. 完全省略ORDER BY,并在代码中进行排序。将涉及解析提供的ORDER BY字符串。如果ORDER BY包含表达式会有问题,但我不记得曾经在我们的项目中看到过,所以可能会被忽略。可能是最慢的解决方案。
  2. 执行不带ORDER BY的查询,将结果集限制为单行。使用结果列列表确定列1是否已在ORDER BY子句中,因此是否添加它。然后运行完整查询。需要解析提供的ORDER BY字符串。查询缓存可能意味着这不会增加显示的开销。
  3. 解析字段列表以获取第一个列名称,并查看它是否出现在ORDER BY子句中。如果字段列表包含*table.*则需要架构查找。如果我们需要组合处理表别名和通配符,可能会太困难。
  4. 解析ORDER BY字符串并查看它是否包含任何主键。如果是这样,它已经被唯一排序,并且不需要添加额外的字段。需要架构查找。
  5. 使用子选择为我们提供我们可以排序的列的新实例。不确定SQL Server是否仍会抱怨这是相同的'尽管如此。

答案 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中进行了一些其他重大更改,但这与此答案无关。)