明确引用不明确的列别名的最不麻烦的方法?
Least cumbersome way to unambiguously reference an ambiguous column alias?
我正在从我未设置的 SQL 服务器数据库中获取一些数据。这是一个生产环境,所以我不想做太多改变。
我正在获取数据并使用获取的数据填充各种类型的对象。有些对象只需要一个 table 的数据;其他人需要加入才能获得所有必要的数据。
有很多table有时间戳列time
,通常存储在datetime
或datetimeoffset
列类型中。这通常是列查询应该排序的依据。不过,有几个 table 时间戳存储在 ndate
列(仅存储日期)和 ntime
列(仅存储时间)中。将这些值相加会产生正确的时间戳。
然后,要使这个 table 的行为与其他的一样并让列映射到对象属性,最简单和最明显的事情就是:
SELECT *, (ndate + ntime) AS time
FROM tableA
WHERE x = z
ORDER BY time DESC
这很好用。但是,如果该对象是需要来自多个 table 的数据的对象之一,就会出现一个明显的问题。如果 tableA
加入 tableB
并且后者有一个 time
列,那么我无法弄清楚如何通过别名 time
列对查询进行排序:
SELECT *, (ndate + ntime) AS time
FROM tableA
LEFT JOIN tableB
WHERE x = z
ORDER BY time DESC
– 会发出一条通知,指出 time
是不明确的,这当然是。
SELECT *, (ndate + ntime) AS time
FROM tableA
LEFT JOIN tableB
WHERE x = z
ORDER BY tableA.time DESC
– 发出一条通知,指出 tableA.time
是无效列,这当然是无效列,因为它不是 table 中实际存在的列。
当然有各种或多或少麻烦的方法来解决这个问题。我设法想出的最简单的方法是在子查询中“包装”tableA
(使用别名列),然后它将有一个可引用的别名,使列明确:
SELECT *
FROM
(SELECT *, (ndate + ntime) AS time
FROM tableA) AS subTable
LEFT JOIN tableB
WHERE x = z
ORDER BY subTable.time DESC
这就是我所说的相当简单,但它仍然使查询的可读性比原来的查询要差很多,这是非常简单的。
很明显,这不是你所说的严重问题,但它仍然让我想知道是否有一种“破坏性”较小的方法来实现相同的最终目标。
有没有一种侵入性更小的方法,它保留了原始查询的更多简单性?
是 - ORDER BY 1
将按 select 的第一列排序,无论它是什么。当然,如果您更改第一列的顺序,则更改
SELECT (tableA.ndate + tableA.ntime) AS time, tableA.*, tableB.*
FROM tableA LEFT JOIN tableB WHERE x = z ORDER BY 1 DESC
由于您不知道 *
中有多少列,所以您先按列排序。
您可能想要添加一个计算列,为您创建 time
。
编辑
我不确定下面的评论中关于外连接的混淆是什么。我在查询中添加了一些详细信息。
您可以使用"cross apply"或简单地使用原始表达式进行排序。即:
SELECT *, (ndate + ntime) AS time
FROM tableA
LEFT JOIN tableB
WHERE x = z
ORDER BY (ndate + ntime) DESC;
注意:这里存在尝试使用 * 在结果集中创建多个 "time" 列的问题。可能您会改为列出您想要的列(无论如何这是推荐的方式)。或者将您的 "time" 命名为其他名称。
我正在从我未设置的 SQL 服务器数据库中获取一些数据。这是一个生产环境,所以我不想做太多改变。
我正在获取数据并使用获取的数据填充各种类型的对象。有些对象只需要一个 table 的数据;其他人需要加入才能获得所有必要的数据。
有很多table有时间戳列time
,通常存储在datetime
或datetimeoffset
列类型中。这通常是列查询应该排序的依据。不过,有几个 table 时间戳存储在 ndate
列(仅存储日期)和 ntime
列(仅存储时间)中。将这些值相加会产生正确的时间戳。
然后,要使这个 table 的行为与其他的一样并让列映射到对象属性,最简单和最明显的事情就是:
SELECT *, (ndate + ntime) AS time
FROM tableA
WHERE x = z
ORDER BY time DESC
这很好用。但是,如果该对象是需要来自多个 table 的数据的对象之一,就会出现一个明显的问题。如果 tableA
加入 tableB
并且后者有一个 time
列,那么我无法弄清楚如何通过别名 time
列对查询进行排序:
SELECT *, (ndate + ntime) AS time
FROM tableA
LEFT JOIN tableB
WHERE x = z
ORDER BY time DESC
– 会发出一条通知,指出 time
是不明确的,这当然是。
SELECT *, (ndate + ntime) AS time
FROM tableA
LEFT JOIN tableB
WHERE x = z
ORDER BY tableA.time DESC
– 发出一条通知,指出 tableA.time
是无效列,这当然是无效列,因为它不是 table 中实际存在的列。
当然有各种或多或少麻烦的方法来解决这个问题。我设法想出的最简单的方法是在子查询中“包装”tableA
(使用别名列),然后它将有一个可引用的别名,使列明确:
SELECT *
FROM
(SELECT *, (ndate + ntime) AS time
FROM tableA) AS subTable
LEFT JOIN tableB
WHERE x = z
ORDER BY subTable.time DESC
这就是我所说的相当简单,但它仍然使查询的可读性比原来的查询要差很多,这是非常简单的。
很明显,这不是你所说的严重问题,但它仍然让我想知道是否有一种“破坏性”较小的方法来实现相同的最终目标。
有没有一种侵入性更小的方法,它保留了原始查询的更多简单性?
是 - ORDER BY 1
将按 select 的第一列排序,无论它是什么。当然,如果您更改第一列的顺序,则更改
SELECT (tableA.ndate + tableA.ntime) AS time, tableA.*, tableB.*
FROM tableA LEFT JOIN tableB WHERE x = z ORDER BY 1 DESC
由于您不知道 *
中有多少列,所以您先按列排序。
您可能想要添加一个计算列,为您创建 time
。
编辑
我不确定下面的评论中关于外连接的混淆是什么。我在查询中添加了一些详细信息。
您可以使用"cross apply"或简单地使用原始表达式进行排序。即:
SELECT *, (ndate + ntime) AS time
FROM tableA
LEFT JOIN tableB
WHERE x = z
ORDER BY (ndate + ntime) DESC;
注意:这里存在尝试使用 * 在结果集中创建多个 "time" 列的问题。可能您会改为列出您想要的列(无论如何这是推荐的方式)。或者将您的 "time" 命名为其他名称。