【发布时间】:2012-12-01 18:36:22
【问题描述】:
如果我写
select ename, to_char(hiredate,'fmDay') as "Day" order by "Day";
然后它根据 Day like 对结果进行排序;从周五开始,然后是周一和上周三, 比如按字符排序。
但我想按星期几排序;从周一到周日。
【问题讨论】:
标签: sql oracle sql-order-by
如果我写
select ename, to_char(hiredate,'fmDay') as "Day" order by "Day";
然后它根据 Day like 对结果进行排序;从周五开始,然后是周一和上周三, 比如按字符排序。
但我想按星期几排序;从周一到周日。
【问题讨论】:
标签: sql oracle sql-order-by
你按你现在的顺序得到它,因为你是按一个字符串排序的(这不起作用,因为你没有从任何东西中选择)。
您可以按用于以数字形式创建星期几的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)
【讨论】:
TO_CHAR(b, 'ID'),以便返回 ISO 8601 星期几,星期一 (1) 和星期日 (7)
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。
【讨论】:
查看TO_CHAR 的其他格式。而不是 'fmDay' 使用 'D' 它将为您提供从 1 到 7 的星期几。然后您可以轻松地对其进行排序。
以下是日期格式列表:http://docs.oracle.com/cd/B19306_01/server.102/b14200/sql_elements004.htm
【讨论】:
NLS_TERRITORY 设置影响哪一天是 1;对于美国来说这是星期天,大多数其他国家是星期一。所以你不能依赖这个
当您可以添加另一列对应天数的 1-7 列然后按此列排序时,为什么会变得复杂...
【讨论】:
我刚刚遇到了同样的要求——按星期几排序查询结果,而不是从星期日开始。我在 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'))
【讨论】:
to_char 的 D 格式掩码将星期几映射到值 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
【讨论】:
如果您希望将星期一始终视为一周的第一天,您可以使用:
-- 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');
【讨论】:
这很简单。
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') 将“星期一”放入名为“星期日”的框中。
【讨论】:
正如所说,它有一个功能:
SELECT *
FROM table
ORDER BY WEEKDAY(table.date);
【讨论】:
TO_CHAR 函数,例如SELECT TO_CHAR(sysdate, 'DAY') FROM dual;
发布答案可能会迟到,但从星期一开始按星期几排序似乎很简单。
select hiredate,dayname(hiredate) from emp order by (dayofweek(hiredate)+5)%7;
为什么要加 5 的答案?
因为,在数字中,周日的值为 1,周一的值为 2……而周六的值为 7
所以,2 + 5 = 7 和 mod(%) 加上 7 将从星期一开始为我们提供新值。
您可以更改此数字以从一周中的任何其他日期开始。
【讨论】:
我改进了 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)
希望这会有所帮助:)
【讨论】:
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.
【讨论】:
我有一些简单的想法希望你喜欢。我不知道您使用的是哪个 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))
【讨论】:
这应该可以在 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;
当然,如果您想要不同的顺序,您只需在之后切换值。
【讨论】:
至少对于 Postgres,要让星期一始终是第 1 天,请使用 TO_CHAR(b, 'ID') 返回 ISO 8601 一周中的某一天 - 星期一 (1) 到星期日 (7)。
这是国际标准组织 (ISO) 的一周中的一天,因此在“ID”中的 D 前面是 I。
【讨论】:
我认为这为时已晚,但如果其他人需要,我会留在这里。
您可以只按星期几订购,但这取决于您的会话区域。
为了显示领土,您可以简单地执行以下查询:
SELECT * FROM V$NLS_PARAMETERS WHERE parameter = 'NLS_TERRITORY';
NLS_TERRITORY 指定区域的名称,其日期和星期编号要遵循其惯例。
回到上一个查询,如果你的值是AMERICA,那么Monday的值就是2。
要从周一到周日订购您的结果,您至少有 2 条道路:
hire_date 减少一天:SELECT * FROM employees ORDER BY TO_CHAR(hire_date - 1, 'd');
FRANCE:ALTER SESSION SET NLS_TERRITORY = 'FRANCE';
SELECT * FROM employees ORDER BY TO_CHAR(hire_date, 'd');
【讨论】:
这是我的解决方案。
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);
【讨论】: