sql - 使用 SQL / PL SQL 验证日期
问题描述
我在验证代码中的日期时遇到问题。它并没有按应有的方式工作。
错误的部分与此有关。
ADD_COMPLEX_SALE_TO_DB - GENERATED UNEXPECTED EXCEPTION
ADD_COMPLEX_SALE_TO_DB - DATE NOT VALID EXCEPTION INCORRECT (WRONG MONTH)
ADD_COMPLEX_SALE_TO_DB - DATE NOT VALID EXCEPTION INCORRECT (WRONG DAY)
我的测试代码是这样的。我有一个不同的输出块,没有问题。
CREATE OR REPLACE PROCEDURE ADD_COMPLEX_SALE_TO_DB (pcustid Number, pprodid Number, pqty Number, pdate Varchar2) AS
QTY_OUTSIDE_RANGE EXCEPTION;
STATUS_NOT_OK EXCEPTION;
INVALID_SALE_DATE EXCEPTION;
vCUST CUSTOMER%ROWTYPE;
vPROD PRODUCT%ROWTYPE;
SALEID SALE%ROWTYPE;
vPROD_ERROR INT := 0;
BEGIN
IF 1 > pqty OR pqty > 999 THEN
RAISE QTY_OUTSIDE_RANGE;
END IF;
SELECT * INTO vCUST
FROM CUSTOMER
WHERE CUSTID = pcustid;
vPROD_ERROR := 1;
IF vCUST.STATUS != 'OK' THEN
RAISE STATUS_NOT_OK;
END IF;
SELECT * INTO vPROD
FROM PRODUCT
WHERE PRODID = pprodid;
IF (LENGTH(pdate) <> 8) THEN
RAISE INVALID_SALE_DATE;
END IF;
INSERT INTO SALE (SALEID, CUSTID, PRODID, QTY, PRICE, SALEDATE)
VALUES (SALE_SEQ.NEXTVAL, pcustid, pprodid, pqty, vPROD.SELLING_PRICE, pdate);
UPD_CUST_SALESYTD_IN_DB(pcustid, (pqty*vPROD.SELLING_PRICE));
UPD_PROD_SALESYTD_IN_DB(pprodid, (pqty*vPROD.SELLING_PRICE));
EXCEPTION
WHEN QTY_OUTSIDE_RANGE THEN
RAISE_APPLICATION_ERROR (-20234, 'Sale Quantity outside valid range');
WHEN STATUS_NOT_OK THEN
RAISE_APPLICATION_ERROR(-20245, 'Customer status is not OK');
WHEN INVALID_SALE_DATE THEN
RAISE_APPLICATION_ERROR(-20252, 'Date not valid');
WHEN NO_DATA_FOUND THEN
IF vPROD_ERROR = 0 THEN
RAISE_APPLICATION_ERROR (-20263, 'Customer ID not found');
ELSE
RAISE_APPLICATION_ERROR (-20271, 'Product ID not found');
END IF;
WHEN OTHERS THEN
RAISE_APPLICATION_ERROR(-20000, SQLERRM);
END;
以下是表创建语句。
CREATE TABLE CUSTOMER (
CUSTID NUMBER
, CUSTNAME VARCHAR2(100)
, SALES_YTD NUMBER
, STATUS VARCHAR2(7)
, PRIMARY KEY (CUSTID)
);
CREATE TABLE PRODUCT (
PRODID NUMBER
, PRODNAME VARCHAR2(100)
, SELLING_PRICE NUMBER
, SALES_YTD NUMBER
, PRIMARY KEY (PRODID)
);
CREATE TABLE SALE (
SALEID NUMBER
, CUSTID NUMBER
, PRODID NUMBER
, QTY NUMBER
, PRICE NUMBER
, SALEDATE DATE
, PRIMARY KEY (SALEID)
, FOREIGN KEY (CUSTID) REFERENCES CUSTOMER
, FOREIGN KEY (PRODID) REFERENCES PRODUCT
);
我该如何去测试日期是否有效?看来我需要以某种方式分解并分别测试月/日/年,但我不确定如何最好地做到这一点。
解决方案
不要通过检查它的长度来检查日期。01/01/21 是有效日期,但 99/01/21 不是。oracle 数据库将尝试进行隐式转换,但将字符串更改为日期并不是一个好习惯。
既然你得到一个字符串,那么传递数据的人必须知道传递日期的格式。如果是 2021 年 2 月 9 日,他会传递 09/02/21、02/09/21、09-FEB-21还是 2021 年 2 月 9 日?所有这些都是有效日期,因此您应该假设 date 传入日期参数的格式是已知的。使用已知的格式,您仍然可以获得无效的日期。假设您的日期格式是 DD/MM/YY,那么 09/02/21 是有效日期,但 50/02/21 不是,09/50/21 也不是。
用于TO_DATE
将字符串转换为数据类型DATE
。Oracle 有几个与日期相关的例外情况。
例子:
DECLARE
l_date_input VARCHAR2(20) := '50/02/21';
l_date DATE;
BEGIN
l_date := TO_DATE(l_date_input,'DD/MM/YY');
END;
/
ORA-01847: day of month must be between 1 and last day of month
ORA-06512: at line 5
01847. 00000 - "day of month must be between 1 and last day of month"
自己试试这个。将 '50/02/21' 更改为 '09/50/21' 并查看引发了什么异常。
现在,让我们将其放在一个仅处理分配的日期部分的示例中。请注意,此示例是一个匿名 pl/sql 块,但可以轻松地将其更改为过程。pragmaEXCEPTION_INIT
允许将用户定义的异常名称与错误代码相关联,因此可以将以下示例中引发的错误映射到您自己的异常。
DECLARE
l_date_input VARCHAR2(2000);
l_date DATE;
--exception thrown: ORA-01843: not a valid month
e_not_a_valid_month EXCEPTION;
PRAGMA EXCEPTION_INIT (e_not_a_valid_month, -01843);
--exception thrown: ORA-01847: day of month must be between 1 and last day of month
e_not_a_valid_day EXCEPTION;
PRAGMA EXCEPTION_INIT (e_not_a_valid_day, -01847);
BEGIN
l_date_input := '01/99/21';
l_date := TO_DATE(l_date_input,'DD/MM/YY');
EXCEPTION
WHEN e_not_a_valid_month THEN
RAISE_APPLICATION_ERROR (-20234, 'DATE NOT VALID EXCEPTION INCORRECT (WRONG MONTH)');
WHEN e_not_a_valid_day THEN
RAISE_APPLICATION_ERROR (-20235, 'DATE NOT VALID EXCEPTION INCORRECT (WRONG DAY)');
WHEN OTHERS THEN
RAISE_APPLICATION_ERROR (-20236, 'GENERATED UNEXPECTED EXCEPTION');
END;
/
ORA-20234: DATE NOT VALID EXCEPTION INCORRECT (WRONG MONTH)
ORA-06512: at line 17
推荐阅读
- python - 如何仅为一个键更新字典中的集合?(Python)
- javascript - 如何在 NodeJS 的对象中嵌入来自方法的响应?
- git - git : 为 git merge --squash -X theirs 禁用自动合并
- javascript - 如何将我的 mongodb 连接到我的笔记本电脑?
- jquery - 不错的选择不工作附加附加
- android - 为什么我们不能在没有 youtube 官方应用的情况下使用 youtube api
- r - 如何将立方体划分为一定的网格数并在 r 中找到每个网格中的元素?
- c++ - 在单链表中的给定节点之后插入节点不起作用
- react-native - react-native 应用程序中未显示警报框
- arrays - 将数组拆分为列 pyspark-array 长度变量