SELECT结果的自定义排序

时间:2013-12-06 22:20:25

标签: sql oracle

我正在使用Pro * C查询,但这个问题应该是通用SQL。我的研究已经走到了尽头,但我想我错过了一些东西。

假设我的服务器有一组学生姓名{"Alice","Charlie","Bob"}。我在Student_Ids表中查询学生的身份证号码:

    SELECT id_no FROM student_ids
        WHERE student_name IN ('Alice','Charlie','Bob');

为了简化服务器端处理,我想按照与学生姓名相同的顺序对结果集进行排序。换句话说,无论表的实际排序或任何特定供应商的实现行为如何,结果集都将为{alice_id_no, charlie_id_no, bob_id_no}

我能想到的唯一解决方案是:

    . . .
    ORDER BY
        CASE WHEN student_name='Alice'   THEN 0
             WHEN student_name='Charlie' THEN 1
             WHEN student_name='Bob'     THEN 2 END;

但在尝试动态生成/运行此查询时,这似乎非常麻烦和麻烦。

有更好的方法吗?

更新我通过预先排序学生的名字给出了一个可怕的例子。我改变名称是故意不分类的。换句话说,我想以非ASC或DESC友好的方式对名称进行排序。

更新II Oracle,但出于知识的考虑,我也在寻找更一般的解决方案。

6 个答案:

答案 0 :(得分:1)

你能这样做吗?

order by student_name

要进行自定义排序,您只需要一个case

ORDER BY (CASE WHEN student_name = 'Alice' THEN 1
               WHEN student_name = 'Bob' THEN 2
               WHEN student_name = 'Charlie' THEN 3
               ELSE 4
          END)

答案 1 :(得分:1)

您为样本数据提供的ORDER BY表达式相当于ORDER BY student_name。那是你的意图吗?

如果你想要一个不按字母顺序排列的自定义排序,我想你可能有这样的意思:

ORDER BY
   CASE
      WHEN student_name = 'Alice' THEN 0
      WHEN student_name = 'Charlie' THEN 1
      WHEN student_name = 'Bob' THEN 2
   END;

您也可以使用派生表,它包含名称以及您想要的顺序。这样你只需要在一个时间内输入名字:

SELECT S.id_no
FROM
   student_ids AS S
   INNER JOIN (
      SELECT Name = 'Alice', Seq = 0 FROM DUAL
      UNION ALL SELECT 'Bob', 2 FROM DUAL
      UNION ALL SELECT 'Charlie', 1 FROM DUAL
   ) AS N
      ON S.student_name = N.Name
ORDER BY
   N.Seq;

您也可以将它们放入临时表中,但在Oracle中可能会有点痛苦。

答案 2 :(得分:0)

为什么不这样:

SELECT id_no FROM student_ids         student_name IN('Alice','Bob','Charlie') ORDER BY student_name

答案 3 :(得分:0)

您可ORDER BYSELECT列表或WHERE条款中的所有列

SELECT id_no 
FROM student_ids 
WHERE student_name IN ('Alice','Bob','Charlie)
ORDER BY id_no;

答案 4 :(得分:0)

添加一个表来保存排序优先级,然后您可以在任何查询中使用sort_priorities(并轻松更新优先级):

CREATE TABLE student_name_sort_priorities (
   student_name VARCHAR2(30) CONSTRAINT student_name_sort_priority__pk PRIMARY KEY,
   sort_priority NUMBER(10)  CONSTRAINT student_name_sort_priority__nn NOT NULL
                             CONSTRAINT student_name_sort_priority__u  UNIQUE
);

(如果您希望对两个值进行等效排序,则不要包含UNIQUE约束。)

INSERT INTO student_name_sort_priorities VALUES ( 'Alice',   0 );
INSERT INTO student_name_sort_priorities VALUES ( 'Charlie', 2 );
INSERT INTO student_name_sort_priorities VALUES ( 'Bob',     1 );

然后,您可以使用student_ids表加入排序优先级表,并使用额外列来执行排序:

SELECT id_no
FROM   student_ids s
       LEFT OUTER JOIN
       student_name_sort_priorities p
       ON (s.student_name = p.student_name)
ORDER BY
       sort_priority NULLS LAST;

我使用了LEFT OUTER JOIN,因此如果student_name_sort_priorities表中没有包含名称,则它不会限制查询返回的行;出于类似原因,在排序中使用NULLS LAST - 任何不在排序优先级表中的学生姓名将返回NULL排序优先级,并放置在排序结束时。如果您不想这样做,请使用INNER JOIN并删除NULLS LAST

答案 5 :(得分:0)

如何使用'varchar'表类型,如下面的内置:

TYPE dbms_debug_vc2coll is table of varchar2(1000);

试验:

SQL> select customer_id, cust_first_name, cust_last_name from customers where cust_first_name in
  2  (select column_value from table(sys.dbms_debug_vc2coll('Frederic','Markus','Dieter')));

CUSTOMER_ID CUST_FIRST_NAME      CUST_LAST_NAME
----------- -------------------- --------------------
        154 Frederic             Grodin
        149 Markus               Rampling
        152 Dieter               Matthau

这似乎迫使订单,但这可能只是运气不好。我不是一个真正的SQL专家。 这个的执行计划使用'collection iterator'而不是典型的大'或':

select customer_id, cust_first_name, cust_last_name from customers where cust_first_name in ('Frederic','Markus','Dieter');
赫斯,海恩。