【问题标题】:How to fetch values of a column into CLOB variable?如何将列的值提取到 CLOB 变量中?
【发布时间】:2020-11-04 00:10:09
【问题描述】:

我试图在 CLOB 变量中传递单个 INTEGER 列的值,以便执行 IN 操作(列的输出大小未知),但出现错误,现在卡住了。首先,我试图在 IN 之后使用 SELECT 语句,但我发现它在 PL/SQL 中不起作用。所以,简而言之,我希望能够检查表中的主键,如果它不存在,则用新值更新现有记录,但如果它已经存在,我不应该这样做。

DoGood Donor 应用程序包含一个页面,该页面允许 管理员在 DD_DONOR 中更改分配给捐赠者的 ID 桌子。创建一个 PL/SQL 块来处理这个任务。包括 异常处理代码,以解决通过尝试 输入重复的捐赠者 ID。如果发生此错误,请显示消息 “这个ID已经分配了。”通过更改捐助者 ID 305 来测试代码。

这是我使用的一张桌子。 DD_DONOR

Name      Null?    Type         
--------- -------- ------------ 
IDDONOR   NOT NULL NUMBER(4)    
FIRSTNAME          VARCHAR2(15) 
LASTNAME           VARCHAR2(30) 
TYPECODE           CHAR(1)      
STREET             VARCHAR2(40) 
CITY               VARCHAR2(20) 
STATE              CHAR(2)      
ZIP                VARCHAR2(9)  
PHONE              VARCHAR2(10) 
FAX                VARCHAR2(10) 
EMAIL              VARCHAR2(25) 
NEWS               CHAR(1)      
DTENTERED          DATE 

这是我的代码:

DECLARE
    all_ids clob;
    newID DD_DONOR.IDDONOR%TYPE;
    fname DD_DONOR.FIRSTNAME%TYPE;
    lname DD_DONOR.LASTNAME%TYPE;    
    CURSOR id IS
    SELECT IDDONOR FROM DD_DONOR;   
BEGIN
    newID := 305;
    fname := 'Thomas';
    lname := 'Sheer';
    
    OPEN id;
    FETCH id BULK COLLECT INTO all_ids;

    IF id%NOTFOUND THEN
        UPDATE DD_DONOR
        SET IDDONOR = newID
        WHERE FIRSTNAME = fname AND LASTNAME = lname;
            DBMS_OUTPUT.PUT_LINE(fname || ' ' || lname || ' ' || 'New ID: ' || newID);
    ELSIF id%FOUND THEN
            DBMS_OUTPUT.PUT_LINE('This ID is already assigned.');
    END IF;

    CLOSE id;
END;

这是错误:

Error report -
ORA-06550: line 14, column 32:
PLS-00497: cannot mix between single row and multi-row (BULK) in INTO list
06550. 00000 -  "line %s, column %s:\n%s"
*Cause:    Usually a PL/SQL compilation error.

我一开始创建的这段代码可以编译,但对表没有任何作用,所以我放弃了它:

DECLARE
    newID DD_DONOR.IDDONOR%TYPE;
    fname DD_DONOR.FIRSTNAME%TYPE;
    lname DD_DONOR.LASTNAME%TYPE;
    
BEGIN
    newID := 305;
    fname := 'Thomas';
    lname := 'Sheer';
    
    UPDATE DD_DONOR
    SET IDDONOR = newID
    WHERE NOT EXISTS (SELECT IDDONOR
                      FROM DD_DONOR
                      WHERE FIRSTNAME = fname AND LASTNAME = lname);
    EXCEPTION 
        WHEN OTHERS THEN
        DBMS_OUTPUT.PUT_LINE('This ID is already assigned.');
END;

输出:

PL/SQL procedure successfully completed.

另一个不起作用的版本:

DECLARE
    newID DD_DONOR.IDDONOR%TYPE;
    fname DD_DONOR.FIRSTNAME%TYPE;
    lname DD_DONOR.LASTNAME%TYPE;
    
BEGIN
    newID := 305;
    fname := 'Thomas';
    lname := 'Sheer';
    
    IF (SELECT IDDONOR FROM DD_DONOR
        WHERE FIRSTNAME = fname AND LASTNAME = lname) = newID
        THEN 
        DBMS_OUTPUT.PUT_LINE('This ID is already assigned.');
    ELSE
        UPDATE DD_DONOR
        SET IDDONOR = newID
        WHERE FIRSTNAME = fname AND LASTNAME = lname;
    END IF;
END;

这种方法有效,但同样不会输出 ID 被占用的错误消息:

SET SERVEROUTPUT ON SIZE 100000
DECLARE
    newID DD_DONOR.IDDONOR%TYPE;
    fname DD_DONOR.FIRSTNAME%TYPE;
    lname DD_DONOR.LASTNAME%TYPE;     
    CURSOR id IS    
    SELECT IDDONOR FROM DD_DONOR
    WHERE FIRSTNAME = fname AND LASTNAME = lname;       
BEGIN
    newID := 305;
    fname := 'Thomas';
    lname := 'Sheer';    
    OPEN id;
    IF SQL%NOTFOUND THEN
        UPDATE DD_DONOR
        SET IDDONOR = newID
        WHERE FIRSTNAME = fname AND LASTNAME = lname;
        DBMS_OUTPUT.PUT_LINE(fname || ' ' || lname || ' ' || 'New ID: ' || newID);
    ELSIF SQL%FOUND THEN
        DBMS_OUTPUT.PUT_LINE('This ID is already assigned.');
    END IF;
    CLOSE id;
END;

这个不行,但我喜欢。看起来应该可以了。

SET SERVEROUTPUT ON SIZE 100000
DECLARE
    newID DD_DONOR.IDDONOR%TYPE;
    fname DD_DONOR.FIRSTNAME%TYPE;
    lname DD_DONOR.LASTNAME%TYPE;    
    CURSOR id IS    
    SELECT IDDONOR FROM DD_DONOR
    WHERE FIRSTNAME = fname AND LASTNAME = lname;    
    all_IDs DD_DONOR%rowtype;    
BEGIN
    newID := 305;
    fname := 'Thomas';
    lname := 'Sheer';    
    OPEN id;    
    LOOP
        FETCH id into all_IDs;
        UPDATE DD_DONOR
        SET IDDONOR = newID
        WHERE FIRSTNAME = fname AND LASTNAME = lname;
        DBMS_OUTPUT.PUT_LINE(fname || ' ' || lname || ' ' || 'New ID: ' || newID);          
        EXIT WHEN id%FOUND;
        DBMS_OUTPUT.PUT_LINE('This ID is already assigned.');
    END LOOP; 
    CLOSE id;
END;
Error report -
ORA-06550: line 15, column 9:
PLS-00394: wrong number of values in the INTO list of a FETCH statement
ORA-06550: line 15, column 9:
PL/SQL: SQL Statement ignored
06550. 00000 -  "line %s, column %s:\n%s"
*Cause:    Usually a PL/SQL compilation error.

【问题讨论】:

  • 这两段代码都存在不少问题。我正在努力理解您要解决的问题。发布一些示例数据和预期结果通常很有帮助。我假设您是学生,这是某种形式的作业。通常,目标是接受idDonorfirstNamelastName 作为输入,并更新指定idDonorfirstNamelastName 列(如果该行已存在)。几乎永远不会更新表的主键。

标签: oracle plsql


【解决方案1】:

您的idNUMBER。您的all_idsCLOB,基本上是一个非常大的字符串字段。查询中的IN 子句适用于离散值的显式列表;这不是字符串搜索之类的东西。您可能想要的是一个集合。

IN 的作用类似于:

WHERE id IN (1, 2, 3)

列表必须是固定长度的。它也可以像这样工作:

WHERE id IN ( SELECT id FROM table2 )

我不太清楚你想做什么。您的第二个查询会将表中的每一行更新为newID,这几乎肯定不是您想要的。如果表中不存在fnamelname,您如何识别要更新的行?

【讨论】:

    【解决方案2】:

    请试试这段代码:

    DECLARE
        newID DD_DONOR.IDDONOR%TYPE;
        oldID DD_DONOR.IDDONOR%TYPE;
        fname DD_DONOR.FIRSTNAME%TYPE;
        lname DD_DONOR.LASTNAME%TYPE;    
    BEGIN
        newID := 305;
        fname := 'Thomas';
        lname := 'Sheer';    
        select
            iddonor
        into
            oldId
        from
            dd_donor
        WHERE iddonor = newId;
        dbms_output.put_line('This ID is already assigned');
    exception
        when NO_DATA_FOUND then
            UPDATE DD_DONOR
            SET IDDONOR = newID
            WHERE FIRSTNAME = fname AND LASTNAME = lname;
            DBMS_OUTPUT.PUT_LINE(fname || ' ' || lname || ' ' || 'New ID: ' || newID); 
    END;
    /
    

    如果您想坚持使用光标的方法,这里是对初始脚本的更改:

    变化在:

    all_ids DD_DONOR.IDDONOR%TYPE - 不需要 CLOB,因为您希望只有一条具有此 ID 的记录。

    游标的声明和调用 - 添加参数以便您能够搜索特定的 id

    DECLARE
        all_ids DD_DONOR.IDDONOR%TYPE;
        newID DD_DONOR.IDDONOR%TYPE;
        fname DD_DONOR.FIRSTNAME%TYPE;
        lname DD_DONOR.LASTNAME%TYPE;    
        CURSOR id(newID in DD_DONOR.IDDONOR%TYPE) IS
        SELECT IDDONOR FROM DD_DONOR where iddonor = newID;   
    BEGIN
        newID := 305;
        fname := 'Thomas';
        lname := 'Sheer';
        
        OPEN id(newId);
        FETCH id  INTO all_ids;
    
        IF id%NOTFOUND THEN
            UPDATE DD_DONOR
            SET IDDONOR = newID
            WHERE FIRSTNAME = fname AND LASTNAME = lname;
                DBMS_OUTPUT.PUT_LINE(fname || ' ' || lname || ' ' || 'New ID: ' || newID);
        ELSIF id%FOUND THEN
                DBMS_OUTPUT.PUT_LINE('This ID is already assigned.');
        END IF;
    
        CLOSE id;
    END;
    /
    

    谢谢

    【讨论】:

    • 太棒了!我从来没有想过使用相同类型的newID和oldID进行比较。
    猜你喜欢
    • 2019-07-29
    • 1970-01-01
    • 2020-11-15
    • 2020-09-05
    • 1970-01-01
    • 2016-07-15
    • 1970-01-01
    • 2019-12-14
    • 1970-01-01
    相关资源
    最近更新 更多