如何在MySQL中调用一个具有游标并应用于所有行的过程?

elcex8rz  于 2023-04-29  发布在  Mysql
关注(0)|答案(1)|浏览(81)

下面是DDL和过程的代码。我想在关系的访问列上应用此过程。我的目标是将日期格式修改为mm/dd/yyyy格式。如何调用函数?更具体地说,我如何将访视列的输入传递给过程?

CREATE TABLE patient (
patno VARCHAR(3), -- patient number (3 digits)
gender VARCHAR(1), -- gender ('M' or 'F')
visit VARCHAR(10), -- visit date (MM/DD/YYYY)

INSERT INTO patient VALUES ('001','m','11/11/1998',88,140,80,'1','0');
INSERT INTO patient VALUES ('002','f','11/13/1998',84,120,78,'X','0');
INSERT INTO patient VALUES ('003','1','10/21/1998',68,190,100,'3','1');
INSERT INTO patient VALUES ('004','F','01/01/1999',101,200,120,'5','A');
DELIMITER //
CREATE PROCEDURE change_date()
BEGIN
    DECLARE done INT DEFAULT FALSE;
    DECLARE patno_var VARCHAR(3);
    DECLARE visit_var VARCHAR(10);
    DECLARE daynr varchar(2);
    DECLARE monthnr varchar(2);
    DECLARE yearnr varchar(4);
    DECLARE temp varchar(2);
    DECLARE cur1 CURSOR FOR SELECT patno, visit FROM project33.patient;
    DECLARE CONTINUE HANDLER FOR NOT FOUND SET done = TRUE;

    OPEN cur1;
    read_loop: LOOP
        FETCH cur1 INTO patno_var, visit_var;
        IF done THEN
            LEAVE read_loop;
        END IF;

        /*split the visit col*/
        SET daynr = SUBSTRING(visit_var, 1, 2);
        SET monthnr = SUBSTRING(visit_var, LOCATE('/', visit_var, 2) + 1, 2);
        SET yearnr = SUBSTRING(visit_var, LOCATE('/', visit_var, 5) + 1, 4);

        /*fix the vars */
        IF monthnr > 12 THEN 
            SET temp = monthnr;
            SET monthnr = daynr;
            SET daynr = temp;

       ELSEIF monthnr IN (01, 03, 05, 07, 08, 10, 12) AND daynr > 31 THEN
            SET daynr = (daynr - 31);
            SET monthnr = (monthnr + 1);
  
        
       ELSEIF monthnr IN (04, 06, 09, 11) AND daynr > 30 THEN
            SET daynr = (daynr - 30);
            SET monthnr = (monthnr + 1);
        END IF;

        SET visit_var = CONCAT(monthnr, '/', daynr, '/', yearnr);
        
        /* update the visit column using the primary key */
        UPDATE patient SET visit = visit_var WHERE patno = patno_var;
    END LOOP;
    CLOSE cur1;
END //
DELIMITER ;

任何帮助都将不胜感激!
然后我调用函数为

call change_date();

这给了我错误操作数应该包含1列

kqlmhetl

kqlmhetl1#

在/*fix vars */部分,如果monthnr〉12,则基于3个SET语句交换月份和日期值。但是,在过程结束时,SET visit_var = CONCAT(monthnr, '/', daynr, '/', yearnr);语句交换了字符串中的月和日的位置(与基表中的日/月/年格式相反),这意味着这些monthnr > 12没有任何变化。现在让我们删除这一部分来演示逻辑,但稍后您将需要它。

CREATE TABLE patient (
patno VARCHAR(3), -- patient number (3 digits),
visit VARCHAR(10) -- visit date (MM/DD/YYYY)
);

INSERT INTO patient VALUES 
 ('005','15/12/1999'),
 ('006','08/32/1998')
 ;
 
 DELIMITER //
drop procedure if exists change_date//
CREATE PROCEDURE change_date()
BEGIN
    DECLARE done INT DEFAULT FALSE;
    DECLARE patno_var VARCHAR(3);
    DECLARE visit_var VARCHAR(10);
    DECLARE daynr varchar(2);
    DECLARE monthnr varchar(2);
    DECLARE yearnr varchar(4);
    DECLARE temp varchar(2);
    DECLARE cur1 CURSOR FOR SELECT patno, visit FROM project33.patient;
    DECLARE CONTINUE HANDLER FOR NOT FOUND SET done = TRUE;

    OPEN cur1;
    read_loop: LOOP
        FETCH cur1 INTO patno_var, visit_var;
        IF done THEN
            LEAVE read_loop;
        END IF;

        /*split the visit col*/
        SET daynr = SUBSTRING(visit_var, 1, 2);
        SET monthnr = SUBSTRING(visit_var, LOCATE('/', visit_var, 2) + 1, 2);
        SET yearnr = SUBSTRING(visit_var, LOCATE('/', visit_var, 5) + 1, 4);

        /* let's remove this monthnr > 12 part for now but later on you'll find it necessary later on
        IF monthnr > 12 THEN 
            SET temp = monthnr; -- 32
            SET monthnr = daynr; -- 8
            SET daynr = temp; -- 32
            */

       IF monthnr IN (1, 3, 5, 7, 8, 10, 12) AND daynr > 31 THEN
            SET daynr = (daynr - 31);
            SET monthnr = (monthnr + 1);
  
        
       ELSEIF monthnr IN (4, 6, 9, 11) AND daynr > 30 THEN
            SET daynr = (daynr - 30);
            SET monthnr = (monthnr + 1);
        END IF;
    
  
    
        SET visit_var = CONCAT(monthnr, '/', daynr, '/', yearnr);
        
    
        /* update the visit column using the primary key */
        UPDATE patient SET visit = visit_var WHERE patno = patno_var;
    END LOOP;
    CLOSE cur1;
END //
DELIMITER ;

-- begin the test
select * from patient;
+-------+------------+
| patno | visit      |
+-------+------------+
| 005   | 15/12/1999 |
| 006   | 08/32/1998 |
+-------+------------+

 call change_date;

select * from patient;
+-------+------------+
| patno | visit      |
+-------+------------+
| 005   | 12/15/1999 |
| 006   | 32/08/1998 |
+-------+------------+

值已更改。然而,日期值“32/08/1998”几乎不合适。这就是为什么我说过程中的if monthnr > 12部分是必要的。您不需要交换month和day的值,但是您肯定需要进行条件检查,例如if monthnr >31 then ...
最后但并非最不重要的是,为了确保您的数据值符合条件,请考虑在更新表之前使用str_to_date函数进行格式检查。

SET visit_var = str_to_date(CONCAT(monthnr, '/', daynr, '/', yearnr),'%c/%e/%Y');

相关问题