背景
解决方案
在数据库中可以用存储过程、触发器、函数实现。
但是前两者处理后的数据已经固化,不符合实际的场景,而函数处理完美的解决了这一问题
???prompt PL/SQL Developer Export Tables for user C##[email protected]
prompt Created by dongj on 2022年4月9日
set feedback off
set define off
prompt Disabling triggers for DW_PATIENT...
alter table DW_PATIENT disable all triggers;
prompt Deleting DW_PATIENT...
delete from DW_PATIENT;
commit;
prompt Loading DW_PATIENT...
insert into DW_PATIENT (patient_id, birth_date, age)
values ('T00785', to_date('21-12-1948', 'dd-mm-yyyy'), null);
insert into DW_PATIENT (patient_id, birth_date, age)
values ('T01394', to_date('26-08-1978', 'dd-mm-yyyy'), null);
insert into DW_PATIENT (patient_id, birth_date, age)
values ('510102', null, null);
insert into DW_PATIENT (patient_id, birth_date, age)
values ('51010201', null, null);
insert into DW_PATIENT (patient_id, birth_date, age)
values ('T00785', to_date('01-01-2022 13:50:00', 'dd-mm-yyyy hh24:mi:ss'), null);
insert into DW_PATIENT (patient_id, birth_date, age)
values ('T01394', to_date('01-08-1988', 'dd-mm-yyyy'), null);
insert into DW_PATIENT (patient_id, birth_date, age)
values ('T01351', to_date('01-07-1956', 'dd-mm-yyyy'), null);
insert into DW_PATIENT (patient_id, birth_date, age)
values ('T00349', to_date('01-08-1985', 'dd-mm-yyyy'), null);
insert into DW_PATIENT (patient_id, birth_date, age)
values ('T00308', to_date('01-06-1977', 'dd-mm-yyyy'), null);
insert into DW_PATIENT (patient_id, birth_date, age)
values ('T00712', to_date('01-05-2021', 'dd-mm-yyyy'), null);
insert into DW_PATIENT (patient_id, birth_date, age)
values ('T00604', to_date('01-04-2022 21:56:00', 'dd-mm-yyyy hh24:mi:ss'), null);
insert into DW_PATIENT (patient_id, birth_date, age)
values ('T00841', to_date('23-02-1964', 'dd-mm-yyyy'), null);
insert into DW_PATIENT (patient_id, birth_date, age)
values ('T00268', to_date('16-02-2022 00:23:00', 'dd-mm-yyyy hh24:mi:ss'), null);
insert into DW_PATIENT (patient_id, birth_date, age)
values ('T00675', to_date('01-09-1920', 'dd-mm-yyyy'), null);
insert into DW_PATIENT (patient_id, birth_date, age)
values ('510102', null, null);
insert into DW_PATIENT (patient_id, birth_date, age)
values ('51010201', null, null);
commit;
prompt 16 records loaded
prompt Enabling triggers for DW_PATIENT...
alter table DW_PATIENT enable all triggers;
set feedback on
set define on
prompt Done
CREATE OR REPLACE PROCEDURE P_TO1_PATIENT(O_RETURN OUT VARCHAR2,BRID IN VARCHAR2,PUTDATE IN DATE) IS
V_BRID VARCHAR2(20) := BRID; --病人ID
V_UPDATE DATE := PUTDATE; --输入更新的时间
V_CSRQ DATE; --出生日期
V_AGE VARCHAR2(20);
V_YEAR VARCHAR2(20);
V_MONTH VARCHAR2(20);
V_DATE VARCHAR2(20);
V_HOUR VARCHAR2(20);
V_MINUTE VARCHAR2(20);
TYPE CUR_TYPE IS REF CURSOR;
CUR_BRXX CUR_TYPE;
BEGIN
OPEN CUR_BRXX FOR
SELECT T.PATIENT_ID, T.BIRTH_DATE
FROM C##DJJ.DW_PATIENT T
WHERE T.PATIENT_ID = V_BRID;
LOOP
FETCH CUR_BRXX
INTO V_BRID, V_CSRQ;
EXIT WHEN CUR_BRXX%NOTFOUND;
IF V_CSRQ IS NULL THEN
UPDATE C##DJJ.DW_PATIENT SET AGE = '未知' WHERE PATIENT_ID = V_BRID;
COMMIT;
ELSE
--YEAR
SELECT FLOOR(MONTHS_BETWEEN(V_UPDATE, V_CSRQ) / 12)
INTO V_YEAR
FROM DUAL;
--MONTHS
SELECT FLOOR(MONTHS_BETWEEN(V_UPDATE, V_CSRQ))
INTO V_MONTH
FROM DUAL;
--DAYS
SELECT FLOOR(TO_NUMBER(ADD_MONTHS(V_UPDATE, -V_MONTH) - V_CSRQ))
INTO V_DATE
FROM DUAL;
--HOURS
SELECT FLOOR(TO_NUMBER(V_UPDATE - V_CSRQ) * 24)
INTO V_HOUR
FROM DUAL;
--MINUTES
SELECT CEIL(TO_NUMBER(V_UPDATE - V_CSRQ) * 24 * 60)
INTO V_MINUTE
FROM DUAL;
IF (V_YEAR = 0 AND V_MONTH = 0 AND V_DATE = 0 AND V_HOUR = 0) THEN
--小于1小时,显示【X分】
UPDATE C##DJJ.DW_PATIENT
SET AGE = V_MINUTE || '分'
WHERE PATIENT_ID = V_BRID;
COMMIT;
ELSIF (V_YEAR = 0 AND V_MONTH = 0 AND V_DATE = 0 AND V_HOUR > 0) THEN
--小于1天,显示【X小时】
UPDATE C##DJJ.DW_PATIENT
SET AGE = V_HOUR || '小时'
WHERE PATIENT_ID = V_BRID;
COMMIT;
ELSIF (V_YEAR = 0 AND V_MONTH < 1 AND V_DATE > 0) THEN
--小于1月,显示【X天】
UPDATE C##DJJ.DW_PATIENT
SET AGE = V_DATE || '天'
WHERE PATIENT_ID = V_BRID;
COMMIT;
ELSIF (V_YEAR = 0 AND V_MONTH >= 1 AND V_DATE = 0) THEN
--小于1岁且天数为0,显示【X月】
UPDATE C##DJJ.DW_PATIENT
SET AGE = V_MONTH || '月'
WHERE PATIENT_ID = V_BRID;
COMMIT;
ELSIF (V_YEAR = 0 AND V_MONTH >= 1 AND V_DATE > 0) THEN
--小于1岁且天数不为0,显示【X月零X天】
UPDATE C##DJJ.DW_PATIENT
SET AGE = V_MONTH || '月零' || V_DATE || '天'
WHERE PATIENT_ID = V_BRID;
COMMIT;
END IF;
--小于等于6岁
IF (V_YEAR > 0 AND V_YEAR <= 6) THEN
--小于等于6岁且月数为0,显示【X岁】
IF ((V_MONTH - V_YEAR * 12) = 0) THEN
UPDATE C##DJJ.DW_PATIENT
SET AGE = V_YEAR || '岁'
WHERE PATIENT_ID = V_BRID;
COMMIT;
ELSIF ((V_MONTH - V_YEAR * 12) > 0) THEN
--小于等于6岁且月数不为0,显示【X岁X月】,考虑闰年
UPDATE C##DJJ.DW_PATIENT
SET AGE = V_YEAR || '岁' || (V_MONTH - V_YEAR * 12) || '月'
WHERE PATIENT_ID = V_BRID;
COMMIT;
END IF;
END IF;
END IF;
--大于6岁显示【X岁】,取整年计算。
IF (V_YEAR > 6) THEN
UPDATE C##DJJ.DW_PATIENT
SET AGE = V_YEAR || '岁'
WHERE PATIENT_ID = V_BRID;
COMMIT;
END IF;
END LOOP;
CLOSE CUR_BRXX;
O_RETURN := '0';
EXCEPTION
WHEN OTHERS THEN
ROLLBACK;
O_RETURN := '-1';
DBMS_OUTPUT.PUT_LINE(SQLERRM);
END P_TO1_PATIENT;
CREATE OR REPLACE TRIGGER TRI_DW_PATIENT
BEFORE INSERT ON C##DJJ.DW_PATIENT
FOR EACH ROW
DECLARE
V_YEAR VARCHAR2(20);
V_MONTH VARCHAR2(20);
V_DATE VARCHAR2(20);
V_HOUR VARCHAR2(20);
V_MINUTE VARCHAR2(20);
BEGIN
IF :NEW.BIRTH_DATE IS NULL THEN
:NEW.AGE := '未知';
ELSE
--YEAR
SELECT FLOOR(MONTHS_BETWEEN(SYSDATE, :NEW.BIRTH_DATE) / 12)
INTO V_YEAR
FROM DUAL;
--MONTHS
SELECT FLOOR(MONTHS_BETWEEN(SYSDATE, :NEW.BIRTH_DATE))
INTO V_MONTH
FROM DUAL;
--DAYS
SELECT FLOOR(TO_NUMBER(ADD_MONTHS(SYSDATE, -V_MONTH) - :NEW.BIRTH_DATE))
INTO V_DATE
FROM DUAL;
--HOURS
SELECT FLOOR(TO_NUMBER(SYSDATE - :NEW.BIRTH_DATE) * 24)
INTO V_HOUR
FROM DUAL;
--MINUTES
SELECT CEIL(TO_NUMBER(SYSDATE - :NEW.BIRTH_DATE) * 24 * 60)
INTO V_MINUTE
FROM DUAL;
IF (V_YEAR = 0 AND V_MONTH = 0 AND V_DATE = 0 AND V_HOUR = 0) THEN
--小于1小时,显示【X分】
:NEW.AGE := V_MINUTE || '分';
ELSIF (V_YEAR = 0 AND V_MONTH = 0 AND V_DATE = 0 AND V_HOUR > 0) THEN
--小于1天,显示【X小时】
:NEW.AGE := V_HOUR || '小时';
ELSIF (V_YEAR = 0 AND V_MONTH < 1 AND V_DATE > 0) THEN
--小于1月,显示【X天】
:NEW.AGE := V_DATE || '天';
ELSIF (V_YEAR = 0 AND V_MONTH >= 1 AND V_DATE = 0) THEN
--小于1岁且天数为0,显示【X月】
:NEW.AGE := V_MONTH || '月';
ELSIF (V_YEAR = 0 AND V_MONTH >= 1 AND V_DATE > 0) THEN
--小于1岁且天数不为0,显示【X月零X天】
:NEW.AGE := V_MONTH || '月零' || V_DATE || '天';
END IF;
--小于等于6岁
IF (V_YEAR > 0 AND V_YEAR <= 6) THEN
--小于等于6岁且月数为0,显示【X岁】
IF ((V_MONTH - V_YEAR * 12) = 0) THEN
:NEW.AGE := V_YEAR || '岁';
COMMIT;
ELSIF ((V_MONTH - V_YEAR * 12) > 0) THEN
--小于等于6岁且月数不为0,显示【X岁X月】,考虑闰年
:NEW.AGE := V_YEAR || '岁' || (V_MONTH - V_YEAR * 12) || '月';
END IF;
END IF;
END IF;
--大于6岁显示【X岁】,取整年计算。
IF (V_YEAR > 6) THEN
:NEW.AGE := V_YEAR || '岁';
END IF;
END;
CREATE OR REPLACE FUNCTION FN_PATIENT_AGE(CSRQ IN DATE, JSRQ IN DATE)
RETURN VARCHAR2 AS
RESULT VARCHAR2(64);
YEARS NUMBER;
MONTHS NUMBER;
DAYS NUMBER;
HOURS NUMBER;
ADULTYEARS NUMBER;
MINUTES NUMBER;
BEGIN
--RESULT
RESULT := '未知';
-- YEARS
SELECT FLOOR(MONTHS_BETWEEN(JSRQ, CSRQ) / 12) INTO YEARS FROM DUAL;
--MONTHS
SELECT FLOOR(MONTHS_BETWEEN(JSRQ, CSRQ)) INTO MONTHS FROM DUAL;
--DAYS
SELECT FLOOR(TO_NUMBER(ADD_MONTHS(JSRQ, -MONTHS) - CSRQ))
INTO DAYS
FROM DUAL;
--HOURS
SELECT FLOOR(TO_NUMBER(JSRQ - CSRQ) * 24) INTO HOURS FROM DUAL;
--MINUTES
SELECT CEIL(TO_NUMBER(JSRQ - CSRQ) * 24 * 60) INTO MINUTES FROM DUAL;
-- ADULTYEARS
SELECT TO_CHAR(JSRQ, 'YYYY') - TO_CHAR(CSRQ, 'YYYY')
INTO ADULTYEARS
FROM DUAL;
--小于1小时,显示【X分】
IF (YEARS = 0 AND MONTHS = 0 AND DAYS = 0 AND HOURS = 0) THEN
RESULT := MINUTES || '分';
END IF;
--小于1天,显示【X小时】
IF (YEARS = 0 AND MONTHS = 0 AND DAYS = 0 AND HOURS > 0) THEN
RESULT := HOURS || '小时';
END IF;
--小于1月,显示【X天】
IF (YEARS = 0 AND MONTHS < 1 AND DAYS > 0) THEN
RESULT := DAYS || '天';
END IF;
--小于1岁且天数为0,显示【X月】
IF (YEARS = 0 AND MONTHS >= 1 AND DAYS = 0) THEN
RESULT := MONTHS || '月';
END IF;
--小于1岁且天数不为0,显示【X月零X天】
IF (YEARS = 0 AND MONTHS >= 1 AND DAYS > 0) THEN
RESULT := MONTHS || '月零' || DAYS || '天';
END IF;
--小于等于6岁
IF (YEARS > 0 AND YEARS <= 6) THEN
--小于等于6岁且月数为0,显示【X岁】
IF ((MONTHS - YEARS * 12) = 0) THEN
RESULT := YEARS || '岁';
--小于等于6岁且月数不为0,显示【X岁X月】,考虑闰年
ELSE
IF ((MONTHS - YEARS * 12) > 0) THEN
RESULT := YEARS || '岁' || (MONTHS - YEARS * 12) || '月';
END IF;
END IF;
END IF;
--大于6岁显示【X岁】,取整年计算。
IF (YEARS > 6) THEN
RESULT := YEARS || '岁';
END IF;
RETURN RESULT;
END;
知识不能白嫖,客官点个关注在走吧