Sort by day of the week from Monday to Sunday

亡梦爱人 提交于 2019-12-03 19:46:17

问题


If I write

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

Then it sorts the result based on Day like; from Friday, then Monday and last Wednesday, like sorting by characters.

But I want to sort it by day of the week; from Monday to Sunday.


回答1:


You're getting it in the order you are because you're ordering by a string (and this wouldn't work because you're not selecting from anything).

You could order by the format model used to create the day of the week in numeric form, D, but as Sunday is 1 in this I would recommend using mod() to make this work.

i.e. assuming the table

create table a ( b date );

insert into a
 select sysdate - level
  from dual
connect by level <= 7;

This would work:

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)

Here's a SQL Fiddle to demonstrate.

In your case your query would become:

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



回答2:


Take a look at other formats for TO_CHAR. Instead of 'fmDay' use 'D' and it will give you the day of the week from 1 to 7. Then you can easily sort on it.

Here's a list of date formats: http://docs.oracle.com/cd/B19306_01/server.102/b14200/sql_elements004.htm




回答3:


I just encountered the same requirement -- to order a query result by day of the week, but not starting with Sunday. I used the following query in Oracle to start w/ Monday. (Modify it to start the ordering w/ any day of the week, e.g., change 'MONDAY' to 'TUESDAY'.)

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

Or:

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



回答4:


The D format mask of to_char maps days of the week to the values 1-7.

But!

The output of this depends on the client's setting for NLS_TERRITORY. The US considers Sunday to be day 1. Whereas most of the rest of the world consider Monday to be the start:

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

Sadly, unlike many other NLS parameters, you can't pass NLS_TERRITORY as the third parameter of 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

So any solution relying on D for sorting is a bug!

To avoid this, subtract the most recent Monday from the date (if today is Monday, the most recent Monday = today). You can do this with the IW format mask. Which returns the start of the ISO week. Which is always a Monday:

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 

For Sunday-Saturday sorting, add one to the date before finding the start of the ISO week:

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 



回答5:


Why to complicate when you can add another column with numbers 1-7 corresponding to days and then sort by this column...




回答6:


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

Assuming that user has a table called classes in that table user has class_id (primary key), class name, Day.




回答7:


If you want Monday to be always treated as first day of week you could use:

-- 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:


It's simple.

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') puts a 'Monday' into a box named 'Sunday'.




回答9:


As it's said, there's a function for it:

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



回答10:


I improved on Ben's answer by giving you a result which starts from 1 rather than 0. The query would be like this:

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);

On the other hand, if you want your week to start from Sunday, then you should use this query:

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)

Hope this helps :)




回答11:


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. 



回答12:


I have some simple idea hope you like it. i don't which sql you are using so please correct syntax error.

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;

I you want to start next week after end a week then just find quarter of month and add in order by clouse.

just for in of find Quarter in(MSSQL): select DatePart(QUARTER, cast(cast(mydate as char(8)) as date))



来源:https://stackoverflow.com/questions/13662451/sort-by-day-of-the-week-from-monday-to-sunday

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!