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。所以它只是没有对