【问题标题】:Sort by day of the week from Monday to Sunday从星期一到星期日按星期几排序
【发布时间】:2012-12-01 18:36:22
【问题描述】:

如果我写

select ename, to_char(hiredate,'fmDay') as "Day" order by "Day";

然后它根据 Day like 对结果进行排序;从周五开始,然后是周一和上周三, 比如按字符排序。

但我想按星期几排序;从周一到周日。

【问题讨论】:

    标签: sql oracle sql-order-by


    【解决方案1】:

    你按你现在的顺序得到它,因为你是按一个字符串排序的(这不起作用,因为你没有从任何东西中选择)。

    您可以按用于以数字形式创建星期几的format model 订购,D,但由于星期日是其中的 1,我建议使用 mod() 来完成这项工作。

    即假设表

    create table a ( b date );
    
    insert into a
     select sysdate - level
      from dual
    connect by level <= 7;
    

    这可行:

    select mod(to_char(b, 'D') + 5, 7) as dd, to_char(b, 'DAY')
      from a
     order by mod(to_char(b, 'D') + 5, 7)
    

    这里有一个SQL Fiddle 来演示。

    在您的情况下,您的查询将变为:

    select ename, to_char(hiredate,'fmDay') as "Day" 
      from my_table
     order by mod(to_char(hiredate, 'D') + 5, 7)
    

    【讨论】:

    • D 格式掩码返回的值受会话的 NLS_TERRITORY 设置影响。运行这个with a UK territory,你会先得到星期二
    • 您可以改用 TO_CHAR(b, 'ID'),以便返回 ISO 8601 星期几,星期一 (1) 和星期日 (7)
    【解决方案2】:
    SELECT
         *
    FROM
         classes
    ORDER BY 
         CASE
              WHEN Day = 'Sunday' THEN 1
              WHEN Day = 'Monday' THEN 2
              WHEN Day = 'Tuesday' THEN 3
              WHEN Day = 'Wednesday' THEN 4
              WHEN Day = 'Thursday' THEN 5
              WHEN Day = 'Friday' THEN 6
              WHEN Day = 'Saturday' THEN 7
         END ASC
    

    假设用户有一个名为 classes 的表,该表用户有 class_id(主键)、类名、Day。

    【讨论】:

      【解决方案3】:

      查看TO_CHAR 的其他格式。而不是 'fmDay' 使用 'D' 它将为您提供从 1 到 7 的星期几。然后您可以轻松地对其进行排序。

      以下是日期格式列表:http://docs.oracle.com/cd/B19306_01/server.102/b14200/sql_elements004.htm

      【讨论】:

      • 这是从星期日开始的一天。
      • NLS_TERRITORY 设置影响哪一天是 1;对于美国来说这是星期天,大多数其他国家是星期一。所以你不能依赖这个
      【解决方案4】:

      当您可以添加另一列对应天数的 1-7 列然后按此列排序时,为什么会变得复杂...

      【讨论】:

      • 根据国家/地区的不同,一周中的第 1 天可能是周一/周日
      【解决方案5】:

      我刚刚遇到了同样的要求——按星期几排序查询结果,而不是从星期日开始。我在 Oracle 中使用以下查询从星期一开始。 (修改它以在一周中的任何一天开始排序,例如,将 'MONDAY' 更改为 'TUESDAY'。)

      SELECT ename, to_char(hiredate, 'fmDAY') AS "Day" 
      FROM emp
      ORDER BY (next_day(hiredate, 'MONDAY') - hiredate) DESC
      

      或者:

      SELECT ename, to_char(hiredate, 'fmDAY') AS "Day"
      FROM emp
      ORDER BY (hiredate - next_day(hiredate, 'MONDAY'))
      

      【讨论】:

        【解决方案6】:

        to_charD 格式掩码将星期几映射到值 1-7。

        但是!

        此输出取决于客户端对 NLS_TERRITORY 的设置。美国认为星期日是第一天。而世界其他大部分地区认为星期一是开始:

        alter session set nls_territory = AMERICA;
        
        with dts as (
          select date'2018-01-01' + level - 1 dt 
          from   dual
          connect by level <= 7
        )
        select to_char ( dt, 'Day' ) day_name,
               to_char ( dt, 'd' ) day_number
        from   dts
        order  by day_number;
        
        DAY_NAME    DAY_NUMBER   
        Sunday       1             
        Monday       2             
        Tuesday      3             
        Wednesday    4             
        Thursday     5             
        Friday       6             
        Saturday     7  
        
        alter session set nls_territory = "UNITED KINGDOM";
        
        with dts as (
          select date'2018-01-01' + level - 1 dt 
          from   dual
          connect by level <= 7
        )
        select to_char ( dt, 'Day' ) day_name,
               to_char ( dt, 'd' ) day_number
        from   dts
        order  by day_number;
        
        DAY_NAME    DAY_NUMBER   
        Monday       1             
        Tuesday      2             
        Wednesday    3             
        Thursday     4             
        Friday       5             
        Saturday     6             
        Sunday       7
        

        遗憾的是,与许多其他 NLS 参数不同,您不能将 NLS_TERRITORY 作为to_char 的第三个参数传递:

        with dts as (
          select date'2018-01-01' dt 
          from   dual
        )
        select to_char ( dt, 'Day', 'NLS_DATE_LANGUAGE = SPANISH' ) day_name
        from   dts;
        
        DAY_NAME    
        Lunes  
        
        with dts as (
          select date'2018-01-01' dt 
          from   dual
        )
        select to_char ( dt, 'Day', 'NLS_TERRITORY = AMERICA' ) day_name
        from   dts;
        
        ORA-12702: invalid NLS parameter string used in SQL function
        

        所以任何依赖D 进行排序的解决方案都是一个错误!

        为避免这种情况,请从日期中减去最近的星期一(如果今天是星期一,则最近的星期一 = 今天)。您可以使用IW 格式掩码来执行此操作。它返回 ISO 周的开始。总是星期一:

        with dts as (
          select date'2018-01-01' + level - 1 dt 
          from   dual
          connect by level <= 7
        )
        select to_char ( dt, 'Day' ) day_name,
               ( dt - trunc ( dt, 'iw' ) ) day_number
        from   dts
        order  by day_number;
        
        DAY_NAME    DAY_NUMBER   
        Monday                   0 
        Tuesday                  1 
        Wednesday                2 
        Thursday                 3 
        Friday                   4 
        Saturday                 5 
        Sunday                   6 
        

        对于周日-周六排序,在找到 ISO 周开始之前的日期加一:

        with dts as (
          select date'2018-01-01' + level - 1 dt 
          from   dual
          connect by level <= 7
        )
        select to_char ( dt, 'Day' ) day_name,
               ( dt - trunc ( dt + 1, 'iw' ) ) day_number
        from   dts
        order  by day_number;
        
        DAY_NAME    DAY_NUMBER   
        Sunday                  -1 
        Monday                   0 
        Tuesday                  1 
        Wednesday                2 
        Thursday                 3 
        Friday                   4 
        Saturday                 5 
        

        【讨论】:

          【解决方案7】:

          如果您希望将星期一始终视为一周的第一天,您可以使用:

          -- Not affected by NLS_TERRITORY
          -- ALTER SESSION SET NLS_TERRITORY="AMERICA";  -- Sunday is first day of week
          -- ALTER SESSION SET NLS_TERRITORY="GERMANY";  -- Monday is first day of week
          
          SELECT *
          FROM tab
          ORDER BY 1+TRUNC(dt)-TRUNC(dt,'IW');
          

          db<>fiddle demo

          【讨论】:

            【解决方案8】:

            这很简单。

            SELECT last_name, hire_date,TO_CHAR(hire_date, 'DAY') DAY
            FROM employees
            ORDER BY TO_CHAR(hire_date - 1, 'd');
            

            TO_CHAR(hire_date - 1, 'd') 将“星期一”放入名为“星期日”的框中。

            【讨论】:

              【解决方案9】:

              正如所说,它有一个功能

              SELECT *
              FROM table
              ORDER BY WEEKDAY(table.date);
              

              【讨论】:

              • 不,没有:SELECT weekday(sysdate) FROM dual; ORA-00904: "WEEKDAY": 标识符无效
              • 函数名称当然可能因每个数据库供应商而异,但我想每个供应商都应该具有可以实现相同目的的日期/时间操作函数。至于 oracle,请考虑 TO_CHAR 函数,例如SELECT TO_CHAR(sysdate, 'DAY') FROM dual;
              【解决方案10】:

              发布答案可能会迟到,但从星期一开始按星期几排序似乎很简单。

              select hiredate,dayname(hiredate) from emp order by (dayofweek(hiredate)+5)%7; 
              

              为什么要加 5 的答案?

              因为,在数字中,周日的值为 1,周一的值为 2……而周六的值为 7

              所以,2 + 5 = 7 和 mod(%) 加上 7 将从星期一开始为我们提供新值。

              您可以更改此数字以从一周中的任何其他日期开始。

              【讨论】:

                【解决方案11】:

                我改进了 Ben 的答案,给你一个从 1 而不是 0 开始的结果。查询将是这样的:

                select 
                    mod(to_char(b, 'D')+ 5, 7) +1 as dd, 
                    to_char(b, 'DAY')
                from a
                order by mod(to_char(b, 'D')+ 5, 7);
                

                另一方面,如果你希望你的一周从星期日开始,那么你应该使用这个查询:

                select 
                    mod(to_char(b, 'D')+ 6, 7) +1 as dd, 
                    to_char(b, 'DAY')
                from a
                order by mod(to_char(b, 'D')+ 6, 7)
                

                希望这会有所帮助:)

                【讨论】:

                  【解决方案12】:
                  with s as (select trunc(sysdate) + level dt from dual connect by level <= 7)
                  select to_char(dt, 'fmDay', 'nls_date_language=English') d
                  from s
                  order by dt - trunc(dt, 'iw');
                  
                  D                                   
                  ------------------------------------
                  Monday
                  Tuesday
                  Wednesday
                  Thursday
                  Friday
                  Saturday
                  Sunday
                  
                  7 rows selected. 
                  

                  【讨论】:

                    【解决方案13】:

                    我有一些简单的想法希望你喜欢。我不知道您使用的是哪个 sql,所以请更正语法错误。

                    select ename, to_char(hiredate,'fmDay') as "Day" from ABC_TABLE
                    JOIN (VALUES (1,'Monday'),(2,'Tuesday'),(3,'Wednesday'),(4,'Thursday'),(5,'Friday'),(6,'Saturday'),(7,'Sunday')) weekdays(seq,[Days]) on
                    ABC_TABLE.to_char(hiredate,'fmDay') = weekdays.[Days]
                    order by weekdays.seq;
                    

                    我想在一周结束后下周开始,然后只需找到月份的季度并按顺序添加。

                    仅用于查找 Quarter in(MSSQL):select DatePart(QUARTER, cast(cast(mydate as char(8)) as date))

                    【讨论】:

                      【解决方案14】:

                      这应该可以在 sql 中解决问题:

                      ORDER BY 
                           CASE DATENAME(dw,<<enter your date variable here>>)
                                WHEN 'Monday' THEN 1
                                WHEN 'Tuesday' THEN 2
                                WHEN 'Wednesday' THEN 3
                                WHEN 'Thursday' THEN 4 
                                WHEN 'Friday' THEN 5 
                                WHEN 'Saturday' THEN 6
                                WHEN 'Sunday' Then 7
                           END ASC;
                      

                      当然,如果您想要不同的顺序,您只需在之后切换值。

                      【讨论】:

                        【解决方案15】:

                        至少对于 Postgres,要让星期一始终是第 1 天,请使用 TO_CHAR(b, 'ID') 返回 ISO 8601 一周中的某一天 - 星期一 (1) 到星期日 (7)。

                        这是国际标准组织 (ISO) 的一周中的一天,因此在“ID”中的 D 前面是 I。

                        https://www.postgresqltutorial.com/postgresql-to_char/

                        【讨论】:

                          【解决方案16】:

                          我认为这为时已晚,但如果其他人需要,我会留在这里。

                          您可以只按星期几订购,但这取决于您的会话区域。

                          为了显示领土,您可以简单地执行以下查询:

                          SELECT * FROM V$NLS_PARAMETERS WHERE parameter = 'NLS_TERRITORY';
                          

                          NLS_TERRITORY 指定区域的名称,其日期和星期编号要遵循其惯例。

                          回到上一个查询,如果你的值是AMERICA,那么Monday的值就是2。

                          要从周一到周日订购您的结果,您至少有 2 条道路:

                          1- 从hire_date 减少一天:

                          SELECT * FROM employees ORDER BY TO_CHAR(hire_date - 1, 'd');
                          

                          2- 将区域更改为以 1 为星期一的值,例如,FRANCE

                          ALTER SESSION SET NLS_TERRITORY = 'FRANCE';
                          
                          SELECT * FROM employees ORDER BY TO_CHAR(hire_date, 'd');
                          

                          【讨论】:

                            【解决方案17】:

                            这是我的解决方案。

                            select ename, to_char(hiredate,'fmDay') "Day"
                            from employees
                            order by DECODE(to_number(to_char(hiredate ,'D'))-1,
                                                                            0, 7,
                                            to_number(to_char(hiredate ,'D'))-1);
                            

                            基本上使用 to_char 函数中的 'D' 格式将日期转换为数字。

                            to_number(to_char(hire_date ,'D')
                            

                            但这会导致星期日为 1,星期一为 2,依此类推,所以我减去 1 使星期一为 1。

                            (to_number(to_char(hire_date ,'D') - 1
                            

                            然后我使用 DECODE 函数基本上说如果 0,然后 7,否则原始数字。这只会使星期日变成 7 而不是 0,其他一切都在适当的位置(星期一是 1,星期二是 2...等等)。

                            DECODE(to_number(to_char(hire_date ,'D'))-1,
                                                                            0, 7,
                                            to_number(to_char(hire_date ,'D'))-1);
                            

                            【讨论】:

                              猜你喜欢
                              • 1970-01-01
                              • 2014-06-26
                              • 1970-01-01
                              • 2011-10-31
                              • 2014-02-23
                              • 1970-01-01
                              • 1970-01-01
                              • 2015-05-13
                              • 2022-08-10
                              相关资源
                              最近更新 更多