วิธีการใช้งบเตรียมไว้ใน MySQL เก็บขั้นตอน?


16

ฉันกำลังใช้ mysql และฉันจำเป็นต้องใช้คอลัมน์ curid ที่ส่งคืนโดยคำสั่งที่เตรียมไว้ในแบบสอบถามภายหลัง ฉันใช้คำสั่งที่เตรียมไว้เพราะเมื่อฉันอ่านมันเป็นวิธีเดียวที่จะส่งผ่านตัวแปรไปยังส่วนคำสั่ง LIMIT ฉันมีขั้นตอนการจัดเก็บที่นี่:

DROP PROCEDURE IF EXISTS fixbalance;
CREATE PROCEDURE fixbalance (userid INT)
  BEGIN
  DECLARE i INT DEFAULT 0;
  DECLARE balance INT DEFAULT 0;
  DECLARE idcnt INT;

  SET idcnt = (SELECT COALESCE(COUNT(id), 0) 
               FROM coupon_operations 
               WHERE user_id = userid);
  IF idcnt <> 0 THEN
    WHILE i <= idcnt DO
      BEGIN
        SET @iter = i;
        SET @user_id = userid; 
        SET @sql = CONCAT('SELECT id AS curid 
                           FROM coupon_operations 
                           WHERE user_id = ? 
                           ORDER BY id ASC 
                           LIMIT ?, 1');
        PREPARE stmt FROM @sql;
        EXECUTE stmt USING @user_id, @iter;
        DEALLOCATE PREPARE stmt;
        SET balance = balance + (SELECT points 
                                 FROM coupon_operations 
                                 WHERE user_id = @user_id 
                                 AND id = @curid);
        UPDATE coupon_operations SET balance = balance;
        SET i = i + 1;
      END;
    END WHILE;
  END IF;
END;
|

สิ่งนี้ใช้ไม่ได้ - ฉันไม่แน่ใจว่าจะผ่านการแก้ปัญหาได้อย่างไร

คำตอบ:


10

ทางออกคือการตั้งค่าตัวแปรในคำสั่งที่เตรียมไว้เหมือนใน:

SET @sql = CONCAT('SET @curid = SELECT id
                                FROM coupon_operations 
                                WHERE user_id = ? 
                                ORDER BY id ASC 
                                LIMIT ?, 1');

1
จุดประสงค์ของCONCATรหัสด้านบนคืออะไร?
Pacerier

@Pacerier คุณไม่จำเป็นต้องใช้CONCATจนกว่าคุณจะผ่านชื่อตารางหรือบางสิ่งบางอย่างเป็นพารามิเตอร์ ตัวอย่าง)CONCAT('select * from ', the_table_name, ' where id>100');
Deckard


0

โปรดลองสิ่งนี้ เพื่อแก้ไข Concatenate, PREPARE และ EXECUTE statement เป็นร้อง ..

CREATE DEFINER=`products`@`localhost` PROCEDURE `generateMeritList`(
   IN `mastercategory_id` INT(11), 
   IN `masterschools_id` INT(11)
 )
 NO SQL
 begin

  declare total int default 0;
  declare conditions varchar(255) default ''; 
  declare finalQuery varchar(60000) default '';

if mastercategory_id > 0 THEN
    SET conditions =  CONCAT(' and app.masterschools_id = ', mastercategory_id);
end if;

SET @finalQuery = CONCAT(
 "SELECT * FROM applications app INNER JOIN masterschools school ON school.id = app.masterschools_id
WHERE 
 (app.status = 'active'", conditions, " LIMIT ",total); 

 PREPARE stmt FROM @finalQuery;
 EXECUTE stmt;
 DEALLOCATE PREPARE stmt;

end

ตัวอย่างเช่นนี้โดยเฉพาะเป็นดี แต่ฉันจะไม่ใช้มันเป็นรูปแบบทั่วไปเนื่องจากความเสี่ยงของการฉีด SQL หากอินพุตเป็นสตริงเช่น VARCHAR แทนที่จะเป็น INT จะทำให้ผู้โจมตีสามารถฉีดรหัส SQL ได้ คำสั่งที่จัดทำขึ้นอย่างถูกต้องปลอดภัยกว่าการต่อสตริงเข้ากับอินพุตภายนอก
Juanal
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.