0

我有一张表,用于存储有关用户的信息。该表具有以下结构:

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;

现在惊喜的顺序已经改变了!

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 列添加到 ORDER BY 来获得稳定的排序。但是 lower() 不应该对排序没有影响吗?

解决方法也为 ORDER BY 使用 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;
4

2 回答 2

2

如果要排序的值相同,则 DBMS 可以自由选择它认为正确的任何顺序(如果一起order by指定 no,则可以自由选择任何顺序)。

因为 order by 中列的所有值都相同,所以结果顺序不稳定。获得稳定订单的唯一方法是包含一个唯一列作为领带的附加订单标准 - 这正是您在添加 id 列时所做的。

为什么顺序变了,只用lower()

从技术角度来看,我猜想应用lower()更改的执行计划以及数据的访问路径。

但同样(只是为了确保):对相同的值进行排序永远不能保证稳定的顺序!

于 2013-04-24T08:01:42.900 回答
1

没有order by clause. 有时看起来可能有(group by在旧版本中愚弄了很多人`,但这只是巧合,绝不能依赖。在您的情况下,您按某些列排序,但您希望该排序中的重复项是进一步隐含地订购,这不会发生 - 或者至少不能依赖。

在这种情况下,Oracle 可能碰巧按照您插入它们的顺序检索您的第一个查询的行,这纯粹是它如何从块中读取数据的副作用,并order by在该集中对它们进行排序而不实际更改它们(或很可能如果它意识到这毫无意义,它会在内部跳过这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

于 2013-04-24T07:55:44.110 回答