【问题标题】:SQL Server order by expressionSQL Server 按表达式排序
【发布时间】:2023-04-03 19:45:01
【问题描述】:

在观看 Troy Hunt 的精彩 course on SQLi 时,我注意到他最终使用此策略来查看表格是否具有特定列:

select * from TableA order by (select top 1 some_column from TableB) desc

这个表达式将被 SQL Server 执行,但是它对 order by 子句有什么作用呢?我已经看到表达式与 order by before 一起使用(case when then else end),但我真的很想了解 SQL 如何在没有任何错误的情况下处理前面的查询......

编辑:提供更多信息,因为我最初的帖子似乎不够清楚:

  1. 我知道这不是通过 SQLi 获取表或列名的最佳策略(这不是我要问的)
  2. 我不想知道如何防止这种情况发生(我已经知道该怎么做)
  3. 我知道按常数值排序没有意义(尽管它允许您运行这些类型的“布尔查询”)
  4. 我真正想知道的是它为什么有效。

所以,回到文档,order by 子句需要一个 order_by_expression,它被描述为:

指定对查询结果集进行排序的列或表达式。排序列可以指定为名称或列别名,或表示列在选择列表中的位置的非负整数。

根据docs,表达式为:

是 SQL Server 数据库引擎评估以获得单个数据值的符号和运算符的组合。简单表达式可以是单个常量、变量、列或标量函数。运算符可用于将两个或多个简单表达式连接成一个复杂表达式。

正如@SMor 所演示的,如果您用简单的select 'A' 替换选择表达式的顺序,则查询会运行:

select * from TableA order by (select 'A') desc

但这不起作用:

select * from TableA order by 'A' desc

那么,问题是:为什么select 'A' 在 order by 子句中被 SQL Server 接受?它不也产生一个常数吗?由于常量是一个表达式,并且考虑到order by 子句的定义,它不应该在两种情况下都抛出错误吗?

谢谢。

【问题讨论】:

  • “这个策略来查看一个表是否有特定的列” - 你这是什么意思?
  • 这被用作回答是或否的注入示例。如果没有表或没有列,则会抛出异常(这在 sql 异常未传播到客户端时很有用)。当 tje 列和表确实存在时,sql 返回记录,尽管我不确定它们是如何排序的......你可以在 ssms 和 aee 上测试这个查询确实被执行(即使通过 select 的顺序返回一个字符串.. .
  • 看起来是一个非常糟糕的策略:如果列名为1); drop TableA; -- 会发生什么,它仍然会导致注入。防止注射的唯一方法是一开始就不要注射。换句话说,您应该始终完全控制 SQL,如果需要动态 SQL,则使用诸如 sys.columnssys.tables 之类的 DMV 来构建查询
  • 再说一次,这不是我要问的......我真正想知道的是为什么查询运行时没有任何错误以及它用于排序。谢谢。
  • 它不使用任何东西进行排序。它在优化过程中识别出它实际上是一个常数并被优化出来。 “在 ORDER BY 列表中遇到了常量表达式”是相当保守的,并且只发生在非常简单的情况下。 ORDER BY (SELECT ...) 有时非常有用。例如与ROW_NUMBER 结合使用,以任意顺序为每一行指定一个唯一编号,无需排序]

标签: sql sql-server sql-order-by


【解决方案1】:

(select top 1 some_column from TableB) 的使用是 标量子查询 的一个示例。这是一个子查询,它只返回一列,最多返回一行。它可以在任何可以使用文字值的地方使用——也许在其他一些地方也是如此。显然,它可以在 order by 中使用,即使 SQL Server 不允许 order by 使用文字值。

最常见的标量子查询类型是相关子查询,它有一个where 子句将子查询连接到外部查询。这不是标量子查询的示例。

事实上,据我所知,这并不是一个有用的例子。它有一个主要缺点,就是使用top 而没有order by。子查询返回的值是不确定的。这似乎是一种不好的做法,如果您试图教人们 SQL,则尤其糟糕。

而且,它可能会被评估一次。因此,子查询将返回一个常量值,并且不会对有意义的排序做出太大贡献。

【讨论】:

  • 当然,所以它会产生一个常量...好的,然后尝试将 select 替换为常量字符串表达式(例如:'a')并让我知道会发生什么...
  • @LuisAbreu 嗯,为什么有人需要这样做并告诉你会发生什么?它会产生一个错误(取决于您如何编码常量),因为按文字排序是逻辑上的废话。您的源使用的查询在逻辑上与按常量排序但不会引发错误。您还可以在选择列表中包含一个常量并按其排序——同样的逻辑废话。 fiddle to demonstrate。有道理吗?
  • 我并不是说它有道理,只是想了解它背后的基本原理。为什么它使用 select 而不是使用常量运行?这些不是表达的例子吗?
  • @LuisAbreu 。 . .你得问问微软。我认为如果你输入一个总是计算相同的 case 表达式,它也可以工作。
  • 你好@GordonLinoff。好吧,因为我不认识 MS 的任何人,所以我认为这是一个很好的提问地方。关于案例,不确定您的意思...
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-10-10
  • 2011-09-20
  • 1970-01-01
  • 1970-01-01
  • 2012-01-30
  • 2019-01-31
相关资源
最近更新 更多