数字乘以常数结果为负数
Number multiplied by constant results in a negative number
我正在尝试计算一年前相应一周的日期。它现在似乎可以正常工作,但有一件事让我很困扰,它最初导致了我通过尝试各种方法修复的几个错误。
问题是,当我不使用 to_number
和 &weekOfYearNow - &weekOfYearThen
并使用此结果计算 lastYearFixed
时,结果将是 -311
而不是7
。为什么会这样?这两个变量 (weekOfYearNow
& weekOfYearThen
) 不是已经是数字了吗?
define today = to_date('30/12/20', 'dd/mm/yy');
define lastYear = add_months(&today, -12);
select &today as "Today" from sys.dual;
select &lastYear as "LastYear" from sys.dual;
define weekOfYearNow = to_number(to_char(&today, 'ww'));
define weekOfYearThen = to_number(to_char(&lastYear, 'ww'));
define weekOfYearOffset = to_number(&weekOfYearNow - &weekOfYearThen); -- <-- must use to_number - but why?
define lastYearFixed = &lastYear + (&weekOfYearOffset * 7); -- <-- this equals -311 if I don't call to_number above
define monday = add_months(sysdate - 7 - to_char(sysdate, 'd') + 2, -12);
define sunday = add_months(sysdate - 7 + to_char(sysdate, 'd'), -12);
select &weekOfYearNow as "WeekOfYearNow" from sys.dual;
select &weekOfYearThen as "WeekOfYearThen" from sys.dual;
select &weekOfYearOffset as "WeekOfYearOffset" from sys.dual;
select &lastYearFixed as "LastYearFixed" from sys.dual;
您不需要(也不应该使用)to_number()
;但您确实需要将第一个表达式括在括号中,如:
define weekOfYearOffset = (&weekOfYearNow - &weekOfYearThen);
define lastYearFixed = &lastYear + (&weekOfYearOffset * 7);
或
define weekOfYearOffset = &weekOfYearNow - &weekOfYearThen;
define lastYearFixed = &lastYear + ((&weekOfYearOffset) * 7);
如果没有其中任何一个,当替换被扩展时,你有效地得到:
define lastYearFixed = &lastYear + (&weekOfYearNow - &weekOfYearThen * 7);
(它实际上扩展了所有这些术语以显示嵌套的 to_date()
和 to_number()
等调用,但为了简洁起见,这给出了想法;重点是它们还不是数字,并且尚未完成任何转换或计算。您可以 set verify on
查看完整的 glory/horror。)
operator precedence 的 *
优先级高于(二进制)-
,这意味着它等同于:
define lastYearFixed = &lastYear + (&weekOfYearNow - (&weekOfYearThen * 7));
所以你要加 weekOfYearNow
并减去 7 次 weekOfYearThen
;而不是将它们之间的差值相加 7 倍。
数量:
select 53 - 52 * 7 as a,
53 - (52 * 7) as b,
(53 - 52) * 7 as c
from dual;
A B C
----- ----- -----
-311 -311 7
当您使用 to_number()
时,您将超越默认优先级,但会进行不必要的隐式转换为字符串并显式转换回数字。仅括号就足以覆盖默认行为。
我想说我打赌这是一件 SQL/Plus 事情(Alex 证明了这一点,感谢 Alex)当我将它转换为 PL/SQL 匿名块并 运行 它时在 Toad 中,它按预期工作。我不打算 post 这个,因为它不是真正的答案,但是比较语言并注意可能会咬你的陷阱有点有趣,你应该记住,所以我会把它留到为了学习。
SET serveroutput ON
DECLARE
today DATE;
lastyear DATE;
weekOfYearNow NUMBER;
weekOfYearThen NUMBER;
weekOfYearOffset NUMBER;
lastYearFixed DATE;
monday DATE;
sunday DATE;
BEGIN
today := TO_DATE('30/12/20', 'dd/mm/yy');
lastYear := ADD_MONTHS(today, -12);
DBMS_OUTPUT.PUT_LINE('Today: ' || today);
DBMS_OUTPUT.PUT_LINE('LastYear: ' || lastYear);
weekOfYearNow := TO_NUMBER(TO_CHAR(today, 'ww'));
weekOfYearThen := TO_NUMBER(TO_CHAR(lastYear, 'ww'));
weekOfYearOffset := weekOfYearNow - weekOfYearThen; -- <-- must use to_number - but why?
lastYearFixed := lastYear + (weekOfYearOffset * 7); -- <-- this equals -311 if I don't call to_number above
monday := ADD_MONTHS(SYSDATE - 7 - TO_CHAR(SYSDATE, 'd') + 2, -12);
sunday := ADD_MONTHS(SYSDATE - 7 + TO_CHAR(SYSDATE, 'd'), -12);
DBMS_OUTPUT.PUT_LINE('WeekOfYearNow: ' || WeekOfYearNow);
DBMS_OUTPUT.PUT_LINE('WeekOfYearThen: ' || WeekOfYearThen);
DBMS_OUTPUT.PUT_LINE('WeekOfYearOffset: ' || WeekOfYearOffset);
DBMS_OUTPUT.PUT_LINE('LastYearFixed: ' || LastYearFixed);
END;
Today: 30-DEC-20
LastYear: 30-DEC-19
WeekOfYearNow: 53
WeekOfYearThen: 52
WeekOfYearOffset: 1
LastYearFixed: 06-JAN-20
我正在尝试计算一年前相应一周的日期。它现在似乎可以正常工作,但有一件事让我很困扰,它最初导致了我通过尝试各种方法修复的几个错误。
问题是,当我不使用 to_number
和 &weekOfYearNow - &weekOfYearThen
并使用此结果计算 lastYearFixed
时,结果将是 -311
而不是7
。为什么会这样?这两个变量 (weekOfYearNow
& weekOfYearThen
) 不是已经是数字了吗?
define today = to_date('30/12/20', 'dd/mm/yy');
define lastYear = add_months(&today, -12);
select &today as "Today" from sys.dual;
select &lastYear as "LastYear" from sys.dual;
define weekOfYearNow = to_number(to_char(&today, 'ww'));
define weekOfYearThen = to_number(to_char(&lastYear, 'ww'));
define weekOfYearOffset = to_number(&weekOfYearNow - &weekOfYearThen); -- <-- must use to_number - but why?
define lastYearFixed = &lastYear + (&weekOfYearOffset * 7); -- <-- this equals -311 if I don't call to_number above
define monday = add_months(sysdate - 7 - to_char(sysdate, 'd') + 2, -12);
define sunday = add_months(sysdate - 7 + to_char(sysdate, 'd'), -12);
select &weekOfYearNow as "WeekOfYearNow" from sys.dual;
select &weekOfYearThen as "WeekOfYearThen" from sys.dual;
select &weekOfYearOffset as "WeekOfYearOffset" from sys.dual;
select &lastYearFixed as "LastYearFixed" from sys.dual;
您不需要(也不应该使用)to_number()
;但您确实需要将第一个表达式括在括号中,如:
define weekOfYearOffset = (&weekOfYearNow - &weekOfYearThen);
define lastYearFixed = &lastYear + (&weekOfYearOffset * 7);
或
define weekOfYearOffset = &weekOfYearNow - &weekOfYearThen;
define lastYearFixed = &lastYear + ((&weekOfYearOffset) * 7);
如果没有其中任何一个,当替换被扩展时,你有效地得到:
define lastYearFixed = &lastYear + (&weekOfYearNow - &weekOfYearThen * 7);
(它实际上扩展了所有这些术语以显示嵌套的 to_date()
和 to_number()
等调用,但为了简洁起见,这给出了想法;重点是它们还不是数字,并且尚未完成任何转换或计算。您可以 set verify on
查看完整的 glory/horror。)
operator precedence 的 *
优先级高于(二进制)-
,这意味着它等同于:
define lastYearFixed = &lastYear + (&weekOfYearNow - (&weekOfYearThen * 7));
所以你要加 weekOfYearNow
并减去 7 次 weekOfYearThen
;而不是将它们之间的差值相加 7 倍。
数量:
select 53 - 52 * 7 as a,
53 - (52 * 7) as b,
(53 - 52) * 7 as c
from dual;
A B C
----- ----- -----
-311 -311 7
当您使用 to_number()
时,您将超越默认优先级,但会进行不必要的隐式转换为字符串并显式转换回数字。仅括号就足以覆盖默认行为。
我想说我打赌这是一件 SQL/Plus 事情(Alex 证明了这一点,感谢 Alex)当我将它转换为 PL/SQL 匿名块并 运行 它时在 Toad 中,它按预期工作。我不打算 post 这个,因为它不是真正的答案,但是比较语言并注意可能会咬你的陷阱有点有趣,你应该记住,所以我会把它留到为了学习。
SET serveroutput ON
DECLARE
today DATE;
lastyear DATE;
weekOfYearNow NUMBER;
weekOfYearThen NUMBER;
weekOfYearOffset NUMBER;
lastYearFixed DATE;
monday DATE;
sunday DATE;
BEGIN
today := TO_DATE('30/12/20', 'dd/mm/yy');
lastYear := ADD_MONTHS(today, -12);
DBMS_OUTPUT.PUT_LINE('Today: ' || today);
DBMS_OUTPUT.PUT_LINE('LastYear: ' || lastYear);
weekOfYearNow := TO_NUMBER(TO_CHAR(today, 'ww'));
weekOfYearThen := TO_NUMBER(TO_CHAR(lastYear, 'ww'));
weekOfYearOffset := weekOfYearNow - weekOfYearThen; -- <-- must use to_number - but why?
lastYearFixed := lastYear + (weekOfYearOffset * 7); -- <-- this equals -311 if I don't call to_number above
monday := ADD_MONTHS(SYSDATE - 7 - TO_CHAR(SYSDATE, 'd') + 2, -12);
sunday := ADD_MONTHS(SYSDATE - 7 + TO_CHAR(SYSDATE, 'd'), -12);
DBMS_OUTPUT.PUT_LINE('WeekOfYearNow: ' || WeekOfYearNow);
DBMS_OUTPUT.PUT_LINE('WeekOfYearThen: ' || WeekOfYearThen);
DBMS_OUTPUT.PUT_LINE('WeekOfYearOffset: ' || WeekOfYearOffset);
DBMS_OUTPUT.PUT_LINE('LastYearFixed: ' || LastYearFixed);
END;
Today: 30-DEC-20
LastYear: 30-DEC-19
WeekOfYearNow: 53
WeekOfYearThen: 52
WeekOfYearOffset: 1
LastYearFixed: 06-JAN-20