【TechTarget中国原创】 问:我有以下查询:
SELECT * FROM mytable WHERE col1 = 'c' UNION SELECT * FROM mytable WHERE col1 = 'a' UNION SELECT * FROM mytable WHERE col1 = 'd' UNION SELECT * FROM mytable WHERE col1 = 'b' |
我怎样才能在同一个选择查询序列中获取结果而不是通过col1进行排序?例如,我需要结果中显示这样的顺序:c,a,d,b。
答:在SQL查询执行过程中,ORDER BY子句是最后执行的。如谚语中说的:“万事俱备,只差东风。”数据库服务器已经检索了列表,在必要的时候还会将它们进行联结、过滤和组合直到对结果进行排序。
一些数据库开发人员相信应该在应用服务器里面进行排序而不是在数据库服务器中。他们说得很有道理。通常,ORDER BY子句需要数据库服务器把结果写入临时表中,反复读取临时表并对它进行排序。管理临时表将耗费在数据库服务器循环方面很多资金,但是让应用服务器进行这种操作会更便宜、更快。数据库服务器只会执行最佳操作、决不会在别的地方浪费。
现在我们来看看UNION查询,不论我们是用ORDER BY子句还是在应用程序进行排序,我们都需要一个运算法则、一种方法来决定排序次序。需要逻辑顺进行以下操作:如果col1中的值为'c',那么就首先对这些行进行操作;如果col1中的值为'a',那么行就排在第二,以此类推。这一操作在UNION查询中很容易进行。
SELECT * , 1 FROM mytable WHERE col1 = 'c' UNION SELECT * , 2 FROM mytable WHERE col1 = 'a' UNION SELECT * , 3 FROM mytable WHERE col1 = 'd' UNION SELECT * , 4 FROM mytable WHERE col1 = 'b' |
你知道这是怎么执行的吗?每行中都有一个额外的列、号码并且在这些号码的基础上对结果进行排序。因此我们就可以将这些行排列成我们想要的顺序。我们现在可以在SQL语句中增加ORDER BY子句,或者返回应用程序结果并对它进行排序。由于应用程序需要知道从哪个列开始,所以最好是对这个列进行命名。
SELECT * , 1 AS sortcol FROM mytable WHERE col1 = 'c' UNION SELECT * , 2 FROM mytable WHERE col1 = 'a' UNION SELECT * , 3 FROM mytable WHERE col1 = 'd' UNION SELECT * , 4 FROM mytable WHERE col1 = 'b' |
从SELECT中将UNION查询结果result set列名置于UNION中,所以我们没有必要再在其他SELECT中配置列别名。
现在有的地方就会截然不同。
SELECT * , CASE WHEN col1 = 'c' THEN 'Curly' WHEN col1 = 'a' THEN 'Larry' WHEN col1 = 'd' THEN 'Moe' WHEN col1 = 'b' THEN 'Shemp' END AS sortcol FROM mytable WHERE col1 IN ( 'c','a','d','b' ) |
当然,这种不同只可能是由于同一个表中所有四个原始的SELECT检索行造成的。如果它们是四个不同的表,那我们就不得不用到UNION。这里我们在表中只有一个SELECT。和固定编码值(hardcoded values)比较,CASE 表达式只能计算另外的毫微秒。但是四个SELECT子句(虽然是同一个表)也有可能真正执行。大部分优化器都会发现这一点,可是为什么它们又会出错呢?
确实我可以在CASE表达式中赋予THEN值一样的号码。对VARCHAR(5) 列进行排序可能会比对1个字节的数值进行排序要慢(虽然区别不是很明显),但是我想名称会非常整洁。