我對 PL/SQL 完全陌生,但我試圖用它來解決我的作業任務。本質上,我想通過案例報表來輸出上一個會計期間的值。這是我整理的內容,我將解釋下面發生的事情:
select
case
when substr(sysdate, 1, 6) >= '01-JAN' and substr(sysdate, 1, 6) <= '31-JAN' then '03'
when substr(sysdate, 1, 6) >= '01-FEB' and substr(sysdate, 1, 6) <= '29-FEB' then '04'
when substr(sysdate, 1, 6) >= '01-MAR' and substr(sysdate, 1, 6) <= '31-MAR' then '05'
when substr(sysdate, 1, 6) >= '01-APR' and substr(sysdate, 1, 6) <= '30-APR' then '06'
when substr(sysdate, 1, 6) >= '01-MAY' and substr(sysdate, 1, 6) <= '31-MAY' then '07'
when substr(sysdate, 1, 6) >= '01-JUN' and substr(sysdate, 1, 6) <= '30-JUN' then '08'
when substr(sysdate, 1, 6) >= '01-JUL' and substr(sysdate, 1, 6) <= '31-JUL' then '09'
when substr(sysdate, 1, 6) >= '01-AUG' and substr(sysdate, 1, 6) <= '31-AUG' then '10'
when substr(sysdate, 1, 6) >= '01-SEP' and substr(sysdate, 1, 6) <= '30-SEP' then '11'
when substr(sysdate, 1, 6) >= '01-NOV' and substr(sysdate, 1, 6) <= '30-NOV' then '01'
when substr(sysdate, 1, 6) >= '01-DEC' and substr(sysdate, 1, 6) <= '31-DEC' then '02'
end actg_period
from table_name
我排除了 10 月,因為這是一個單獨的條件。上面發生的情況是,今天的 sysdate 值(我已經在我們的資料庫中驗證了這一點)是“01-JUN”,并且應該凈輸出值“08”。然而,它所做的是凈值'03'。我昨天(5 月 31 日)運行了同樣的代碼,它得到了預期的值或“07”。鑒于我對案例陳述的經驗很少,我無法確定問題是什么。
任何建議表示贊賞。
uj5u.com熱心網友回復:
將日期轉換為字串并進行比較通常會導致問題。
你說今天(2022 年 6 月 1 日)你得到 '01-JUN' SUBSTR(SYSDATE, 1, 6)。這是絕對正確的(如果我們假設您的系統日期格式類似于“DD-MON-YYYY”)。
然后你說你很驚訝你03從你的 CASE 運算式中得到了。要問的問題是,“字串'01-JAN'和'31-JAN`之間是否存在字串'01-JUN'”?答案是“是的,是的”。那么,為什么會出現混亂呢?
好吧,我們明白為什么。你真正想說的是:
SYSDATE 的日期部分 ('01') 是否在 '01' 和 '31' 之間,并且 SYSDATE 的月份部分 ('JUN') = 'JAN'?如果這樣問,答案是否定的,不是,但這不是您的代碼所做的。
這就是為什么我們不將日期轉換為字串來比較它們的原因——因為我們得到的結果總是正確的,但往往令人驚訝。
有更好的方法可以做到這一點,而且每個方法都不涉及將日期轉換為字串。
其他人提出了很好的建議。
但我還有一個,最后只使用了一點數學和字符轉換:
ACCTG_PERIOD := TO_CHAR(MOD(EXTRACT(MONTH FROM SYSDATE) 2, 12), '09');
uj5u.com熱心網友回復:
問題是您正在比較字串,而不是日期。昨天,substr(sysdate, 1, 6)給了你 - 假設你的會話 NLS 設定仍然是默認設定,這對你來說不是一個安全的假設,特別是對于運行此代碼的任何其他人 - 字串 '31-MAY'。
當作為一個恰好不適合任何早期括號的字串進行比較時。
作為演示,如果您按字母順序排列每個月的前三天,格式為 DD-MON-YY,您會得到:
01-APR-22
01-AUG-22
01-DEC-22
01-FEB-22
01-JAN-22
01-JUL-22
01-JUN-22
01-MAR-22
01-MAY-22
01-NOV-22
01-OCT-22
01-SEP-22
02-APR-22
02-AUG-22
02-DEC-22
...
02-SEP-22
03-APR-22
03-AUG-22
...
03-SEP-22
僅使用每個月的第一天,您的第一個括號 '01-JAN' 到 '31-JAN' 包括字串(不是日期):
01-JAN-22
01-JUL-22
01-JUN-22
01-MAR-22
01-MAY-22
01-NOV-22
01-OCT-22
01-SEP-22
以及那幾個月的所有其他日期。
第二個括號 '01-FEB' 到 '29-FEB' 包括:
01-FEB-22
01-JAN-22
01-JUL-22
01-JUN-22
01-MAR-22
01-MAY-22
01-NOV-22
01-OCT-22
以及那些月份中的幾乎所有其他日期 - 每個月 29 日之前的所有日期,因此不包括 30 日和 31 日。
第三個 '01-MAR' 到 '31-MAR' 包含:
01-MAR-22
01-MAY-22
01-NOV-22
01-OCT-22
以及那幾個月的所有其他日期。
第四個 '01-APR' 到 '30-APR' 包含所有這些:
01-APR-22
01-AUG-22
01-DEC-22
01-FEB-22
01-JAN-22
01-JUL-22
01-JUN-22
01-MAR-22
01-MAY-22
01-NOV-22
01-OCT-22
以及那些月份中除 31 日以外的所有其他日期。
第五個 '01-MAY' 到 '31-MAY' 包含:
01-MAY-22
01-NOV-22
01-OCT-22
以及那幾個月的所有其他日期。
等等。
當您比較昨天日期的字串版本“31-MAY”時,它不適合第一個括號,因為按字母順序,“31-M”不在“01-J”和“31-J”之間,因為字母表中“M”在“J”之后。對于第二個括號,它甚至不需要查看月份,它可以在第一個字符之后停止比較 - '3' 在 '2' 之后,所以它不適合那個括號。第三個括號更令人興奮,因為它必須檢查整個字串 - 但是,'31-MAY' 仍然不在 '01-MAR' 和 '31-MAR' 之間,因為 'Y' 在 'R' 之后。第四個括號可能在兩個字符后被拒絕,因為 '1' 在 '0' 之后。它終于可以匹配第五個括號,這是您所期望的。
但是,當您比較與您的第一個括號匹配的今天日期的字串版本“01-JUN”時,因為“01-JUN”包含在第一個串列中。
您還沒有說要如何處理 10 月,但對于其余部分,您不需要轉換的 case 運算式;你可以做:
TO_CHAR(ADD_MONTHS(TRUNC(SYSDATE, 'MM'), 2), 'MM')
今天給出了'08'。您可以對其進行修改以使 10 月成為一個特例——這取決于您要如何對待它;添加不同的月數,或具有特定值的 case 運算式。
uj5u.com熱心網友回復:
您可以只使用EXTRACT檢查月份:
SELECT CASE EXTRACT(MONTH FROM sysdate)
WHEN 1 THEN '03'
WHEN 2 THEN '04'
...
WHEN 12 THEN '02'
END AS actg_period
FROM table_name;
這使您的查詢更短且更易于閱讀。
uj5u.com熱心網友回復:
你為什么要子串 a DATE?只需比較日期:
SELECT
CASE
WHEN SYSDATE >= TO_DATE('01-JAN','DD-MON') AND SYSDATE <= TO_DATE('31-JAN','DD-MON') THEN '03'
WHEN SYSDATE >= TO_DATE('01-FEB','DD-MON') AND SYSDATE <= ADD_MONTHS(TO_DATE('01-FEB','DD-MON'),1) -1 THEN '04'
WHEN SYSDATE >= TO_DATE('01-MAR','DD-MON') AND SYSDATE <= TO_DATE('31-MAR','DD-MON') THEN '05'
WHEN SYSDATE >= TO_DATE('01-APR','DD-MON') AND SYSDATE <= TO_DATE('30-APR','DD-MON') THEN '06'
WHEN SYSDATE >= TO_DATE('01-MAY','DD-MON') AND SYSDATE <= TO_DATE('31-MAY','DD-MON') THEN '07'
WHEN SYSDATE >= TO_DATE('01-JUN','DD-MON') AND SYSDATE <= TO_DATE('30-JUN','DD-MON') THEN '08'
WHEN SYSDATE >= TO_DATE('01-JUL','DD-MON') AND SYSDATE <= TO_DATE('31-JUL','DD-MON') THEN '09'
WHEN SYSDATE >= TO_DATE('01-AUG','DD-MON') AND SYSDATE <= TO_DATE('31-AUG','DD-MON') THEN '10'
WHEN SYSDATE >= TO_DATE('01-SEP','DD-MON') AND SYSDATE <= TO_DATE('30-SEP','DD-MON') THEN '11'
WHEN SYSDATE >= TO_DATE('01-NOV','DD-MON') AND SYSDATE <= TO_DATE('30-NOV','DD-MON') THEN '01'
WHEN SYSDATE >= TO_DATE('01-DEC','DD-MON') AND SYSDATE <= TO_DATE('31-DEC','DD-MON') THEN '02'
END actg_period
FROM table_name ;
轉載請註明出處,本文鏈接:https://www.uj5u.com/gongcheng/484719.html
上一篇:每X段后插入廣告PHP
下一篇:如何計算每行不同起點之前的事件?
