Oracle10g 为什么lower()的使用会改变resultset的顺序?
我有一个存储用户信息的表。该表具有以下结构:Oracle10g 为什么lower()的使用会改变resultset的顺序?,oracle10g,Oracle10g,我有一个存储用户信息的表。该表具有以下结构: CREATE TABLE PERSONS ( ID NUMBER(20, 0) NOT NULL, FIRSTNAME VARCHAR2(40), LASTNAME VARCHAR2(40), BIRTHDAY DATE, CONSTRAINT PERSONEN_PK PRIMARY KEY (ID) ENABLE ); 插入一些测试数据后: SET DEFINE OFF; Insert into PERSON
CREATE TABLE PERSONS
(
ID NUMBER(20, 0) NOT NULL,
FIRSTNAME VARCHAR2(40),
LASTNAME VARCHAR2(40),
BIRTHDAY DATE,
CONSTRAINT PERSONEN_PK PRIMARY KEY
(ID)
ENABLE
);
插入一些测试数据后:
SET DEFINE OFF;
Insert into PERSONS (ID,FIRSTNAME,LASTNAME,BIRTHDAY) values ('1','Max','Mustermann',to_date('31.10.89','DD.MM.RR'));
Insert into PERSONS (ID,FIRSTNAME,LASTNAME,BIRTHDAY) values ('2','Max','Mustermann',to_date('31.10.89','DD.MM.RR'));
Insert into PERSONS (ID,FIRSTNAME,LASTNAME,BIRTHDAY) values ('3','Carl','Carlchen',to_date('01.01.12','DD.MM.RR'));
Insert into PERSONS (ID,FIRSTNAME,LASTNAME,BIRTHDAY) values ('4','Max','Mustermann',to_date('31.10.89','DD.MM.RR'));
Insert into PERSONS (ID,FIRSTNAME,LASTNAME,BIRTHDAY) values ('5','Max','Mustermann',to_date('31.10.89','DD.MM.RR'));
Insert into PERSONS (ID,FIRSTNAME,LASTNAME,BIRTHDAY) values ('6','Carl','Carlchen',to_date('01.01.12','DD.MM.RR'));
我想选择给定用户的所有副本。让我们以“Max Mustermann”为例:
SELECT p.id,p.firstname,p.lastname,p.birthday
FROM persons p
WHERE p.firstname = 'Max'
AND p.lastname = 'Mustermann'
AND p.birthday = to_date('31.10.1989','dd.mm.yyyy')
ORDER BY p.firstname,p.lastname;
这给了我这样一个结果:
id first last birthday
=================================
1 Max Mustermann 31.10.89
2 Max Mustermann 31.10.89
4 Max Mustermann 31.10.89
5 Max Mustermann 31.10.89
SELECT p.id,p.firstname,p.lastname,p.birthday
FROM persons p
WHERE lower(trim(p.firstname)) = lower(trim('mAx '))
AND lower(trim(p.lastname)) = lower(trim(' musteRmann '))
AND p.birthday = to_date('31.10.1989','dd.mm.yyyy')
ORDER BY p.lastname,p.firstname;
我想进行不区分大小写的比较,因此我使用lower(和trim)更改查询,如下所示:
id first last birthday
=================================
1 Max Mustermann 31.10.89
2 Max Mustermann 31.10.89
4 Max Mustermann 31.10.89
5 Max Mustermann 31.10.89
SELECT p.id,p.firstname,p.lastname,p.birthday
FROM persons p
WHERE lower(trim(p.firstname)) = lower(trim('mAx '))
AND lower(trim(p.lastname)) = lower(trim(' musteRmann '))
AND p.birthday = to_date('31.10.1989','dd.mm.yyyy')
ORDER BY p.lastname,p.firstname;
现在,令人惊讶的是,订单已经改变了
id first last birthday
=================================
1 Max Mustermann 31.10.89
5 Max Mustermann 31.10.89
4 Max Mustermann 31.10.89
2 Max Mustermann 31.10.89
为什么仅通过使用lower()(在不使用trim()的情况下使用相同的结果)订单会发生变化!?我可以通过将id列添加到orderby来获得稳定的排序。但是lower()不应该对排序没有影响吗
解决方法是同时使用“订购人”的“id”列:
SELECT p.id,p.firstname,p.lastname,p.birthday
FROM persons p
WHERE p.firstname = 'Max'
AND p.lastname = 'Mustermann'
AND p.birthday = to_date('31.10.1989','dd.mm.yyyy')
ORDER BY p.firstname,p.lastname,p.id;
SELECT p.id,p.firstname,p.lastname,p.birthday
FROM persons p
WHERE lower(trim(p.firstname)) = lower(trim('mAx '))
AND lower(trim(p.lastname)) = lower(trim(' musteRmann '))
AND p.birthday = to_date('31.10.1989','dd.mm.yyyy')
ORDER BY p.lastname,p.firstname,p.id;
没有
orderby子句
就没有排序。有时看起来可能有(groupby
在旧版本中愚弄了很多人,但这只是巧合,不能依赖。在您的情况下,您是按某些列排序的,但您希望该排序中的重复项被进一步隐式排序,这不会发生,或者至少不能依赖
在这种情况下,Oracle可能恰好按照您插入行的顺序检索第一次查询的行,这纯粹是它从块中读取数据的副作用,orderby
在该集中对行进行排序,而不实际更改它们(或者,如果意识到这毫无意义,它很可能会在内部跳过order by
步骤;解释计划会告诉你这一点)
如果您更改了创建记录的顺序:
...
Insert into PERSONS (ID,FIRSTNAME,LASTNAME,BIRTHDAY) values
('5','Max','Mustermann',to_date('31.10.89','DD.MM.RR'));
Insert into PERSONS (ID,FIRSTNAME,LASTNAME,BIRTHDAY) values
('4','Max','Mustermann',to_date('31.10.89','DD.MM.RR'));
...
然后结果“顺序”也会改变:
SELECT p.id,p.firstname,p.lastname,p.birthday
FROM persons p
WHERE p.firstname = 'Max'
AND p.lastname = 'Mustermann'
AND p.birthday = to_date('31.10.1989','dd.mm.yyyy')
ORDER BY p.firstname,p.lastname;
ID FIRSTNAME LASTNAME BIRTHDAY
---------- -------------------- -------------------- ---------
1 Max Mustermann 31-OCT-89
2 Max Mustermann 31-OCT-89
5 Max Mustermann 31-OCT-89
4 Max Mustermann 31-OCT-89
一旦你有了这个函数,事情就发生了足够的变化,以至于那次愉快的意外事件就消失了,即使记录是按id
顺序插入的(这与数据库内部无关)。lower()
没有改变顺序,你也不会再幸运了
除非在
order by
子句中完全指定订单,否则您不能期望或依赖订单。没有order by子句,就没有订单。有时看起来可能会有(group by
在旧版本中愚弄了很多人,但这只是巧合,不能依赖。在您的情况下,您是按某些列排序的,但您希望该排序中的重复项被进一步隐式排序,这不会发生,或者至少不能依赖
在这种情况下,Oracle可能恰好按照您插入行的顺序检索第一次查询的行,这纯粹是它从块中读取数据的副作用,orderby
在该集中对行进行排序,而不实际更改它们(或者,如果意识到这毫无意义,它很可能会在内部跳过order by
步骤;解释计划会告诉你这一点)
如果您更改了创建记录的顺序:
...
Insert into PERSONS (ID,FIRSTNAME,LASTNAME,BIRTHDAY) values
('5','Max','Mustermann',to_date('31.10.89','DD.MM.RR'));
Insert into PERSONS (ID,FIRSTNAME,LASTNAME,BIRTHDAY) values
('4','Max','Mustermann',to_date('31.10.89','DD.MM.RR'));
...
然后结果“顺序”也会改变:
SELECT p.id,p.firstname,p.lastname,p.birthday
FROM persons p
WHERE p.firstname = 'Max'
AND p.lastname = 'Mustermann'
AND p.birthday = to_date('31.10.1989','dd.mm.yyyy')
ORDER BY p.firstname,p.lastname;
ID FIRSTNAME LASTNAME BIRTHDAY
---------- -------------------- -------------------- ---------
1 Max Mustermann 31-OCT-89
2 Max Mustermann 31-OCT-89
5 Max Mustermann 31-OCT-89
4 Max Mustermann 31-OCT-89
一旦你有了这个函数,事情就发生了足够的变化,以至于那次愉快的意外事件就消失了,即使记录是按id
顺序插入的(这与数据库内部无关)。lower()
没有改变顺序,你也不会再幸运了
除非您在order by
子句中完全指定订单,否则您不能期望或依赖订单。如果要按订单排序的值相同,则DBMS可以自由选择其认为正确的任何订单(同样,如果没有一起指定order by
,则可以自由选择任何订单)
由于order by中列的所有值都相同,因此结果顺序不稳定。获得稳定顺序的唯一方法是将唯一列作为领带的附加顺序标准—这正是添加id列时所做的
为什么仅仅通过使用lower()命令,顺序就改变了
从技术角度来看,我猜应用lower()
会改变执行计划,从而改变数据的访问路径
但是,同样(只是为了确保):按相同的值排序永远不能保证稳定的顺序!如果要按相同的值排序,则DBMS可以自由选择其认为正确的任何顺序(如果没有一起指定order by
,则可以自由选择任何顺序)
由于order by中列的所有值都相同,因此结果顺序不稳定。获得稳定顺序的唯一方法是将唯一列作为领带的附加顺序标准—这正是添加id列时所做的
为什么仅仅通过使用lower()命令,顺序就改变了
从技术角度来看,我猜应用lower()
会改变执行计划,从而改变数据的访问路径
但再一次(只是为了确保):按相同的值排序永远不能保证稳定的顺序!他使用的是orderby
他只是没有得到稳定的顺序,因为排序的值都是相同的。@a_horse_和_no_name-是的,我后来提到过,但第一段有误导性,谢谢。正如@a_horse_和_no_name所说的,我确实使用了orderby。所以它是只是没有按照我想要的方式排序,因为对于相同的数据没有明确的顺序?而且只要我添加id字段,就有明确的顺序,对吗?@elton-没错。你可能还对经常链接Tom Kyte关于排序的几篇文章感兴趣,比如和,尽管至少你比他咆哮的大多数人更努力。。.*8-)他使用的是一个orderby
他只是没有得到一个稳定的顺序,因为有序的值都是相同的。@a_horse_和_no_name-是的,我后来提到过,但第一段是误导性的,谢谢。正如@a_horse_和_no_name所说的,我确实使用了orderby。所以它只是没有对