【问题标题】:Oracle Cursors : Invalid IdentifierOracle 游标:标识符无效
【发布时间】:2021-03-13 07:11:26
【问题描述】:

我需要编写代码来增加 40 岁以上员工的工资。

这是我的代码:

DECLARE  
CURSOR kurs IS SELECT  ID_PRACOWNIKA , pensja_BR, wiek FROM PRACOWNICY p , OSOBY o ;
ID_PRACOWNIKA decimal(2):=0;
pensja DECIMAL(8,2);
wiek DECIMAL(2);

BEGIN
    OPEN kurs;
LOOP

   IF wiek > 40 
   THEN
      UPDATE PRACOWNICY 
       SET pensja = PENSJA_BR * 1.02
      WHERE ID_PRACOWNIKA = ID_PRACOWNIKA;

      dbms_OUTPUT.put_line( ID_PRACOWNIKA|| '-'||pensja);
     END IF;
 ID_PRACOWNIKA := ID_PRACOWNIKA+1;
 EXIT WHEN ID_PRACOWNIKA=6;
  END LOOP;
   CLOSE kurs;
   END;

很遗憾,我遇到了 SQL 错误

SQL Error [6550] [65000]: ORA-06550: line 14, column 12:
PL/SQL: ORA-00904: "PENSJA": invalid identifier
ORA-06550: line 13, column 7:
PL/SQL: SQL Statement ignored

Osoby 表结构:

Id_osoby NUMBER CONSTRAINT osoby_pk PRIMARY KEY,
Imie VARCHAR2(15) NOT NULL,
Nazwisko VARCHAR2(30) NOT NULL,
Wiek NUMBER NOT NULL CONSTRAINT ch_wiek CHECK((Wiek>=0) AND (Wiek<=125)),
Stan_cywilny VARCHAR2(12) NOT NULL,
Telefon VARCHAR2(20),
Pesel CHAR(11) NOT NULL CONSTRAINT osoba_uni UNIQUE,
Id_adresu NUMBER NOT NULL,
CONSTRAINT os_ad_fk FOREIGN KEY (Id_adresu) REFERENCES Adresy(Id_adresu)

实用表结构:

Id_pracownika NUMBER CONSTRAINT pracownik_pk PRIMARY KEY,
Id_osoby NUMBER NOT NULL CONSTRAINT pr_unique UNIQUE,
Id_stanowiska NUMBER NOT NULL,
Staz NUMBER NOT NULL CONSTRAINT ch_staz CHECK((Staz>=0) AND (Staz<=45)),
Pensja_br NUMBER NOT NULL CONSTRAINT pen_staz CHECK(Pensja_br>=1226),
CONSTRAINT pr_os_fk FOREIGN KEY (Id_osoby) REFERENCES Osoby(Id_osoby),
CONSTRAINT pr_st_fk FOREIGN KEY (Id_stanowiska) REFERENCES Stanowiska(Id_stanowiska)

【问题讨论】:

  • 您能分享一下您的代码在做什么吗?这段代码有什么期望?
  • 我的代码更改了 Pensja_br 列 Wiek > 40 的位置,然后显示 id_pracownika 和增加的 pensja。 dbms_OUTPUT.put_line(ID_PRACOWNIKA|| '-'||pensja);
  • 能否分享一下代码中使用的两个表的表结构?必须有一些比你正在做的更简单的方法。您在游标查询中使用了交叉联接。这在 DB 中也不是显而易见的事情。
  • 当然,我刚刚将它添加到主要问题中。

标签: oracle dbeaver cursors


【解决方案1】:

我认为是 UPDATE 子句导致了问题(错误描述说错误在脚本的第 14 行)

SET pensja = PENSJA_BR * 1.02

正如我在开头看到的那样,在 PRACOWNICY 表中有一个名为 pensja_BR 的列,但您正在尝试更新“pensija”列。表中可能不存在。

这里要提到的另一件事是光标中有一个笛卡尔连接,因为您要连接两个表而没有任何连接/位置条件

UPD:循环可能在这里也不起作用,因为您没有从中获取数据。打开游标不会自动获取数据。您必须每次在循环中显式获取它

open kurs;
loop
  fetch kurs into some_variable
  ...
end loop;

或者使用另一个 for..loop 语句来循环游标

for k in kurs loop
...
end loop;

因此,您需要使用以下 where 子句更新游标定义

WHERE p.id_osoby = o.id_osoby and wiek > 40

然后删除 IF > 40 语句,你不再需要它了。 在 DECLARE 中声明一个 rowtype 变量: kurs_l kurs%rowtype;

在 PLSQL 中: 打开库尔; 环形 将 kurs 提取到 kurs_l 中; 当 kurs%notfound 时退出;

  ... do your stuff ...
end loop;
close kurs;

【讨论】:

  • 好的,谢谢,错误已修复。但是现在我如何将 PENSJA_BR * 1.02 分配给一个变量,例如 pensja?
  • 哦,我怎么能这样?每次都打开光标?
  • @Tacoo,请稍等。我会更新答案
【解决方案2】:

我不太确定预期的结果是什么,但我有疑问。如果您已经从表中检索了 ID_PRACOWNIKA 、 pensja_BR 、 wiek 列,为什么还要创建一些具有相同名称的变量?

现在,我从您的问题中了解到的是,您尝试将 PENSJA_BR 列更改为 WIEK 列中值 >40 的每一行的 PENSJA_BR * 1.02 值。

我认为以下代码可能会帮助您解决问题。我已经在我的测试环境中对其进行了测试,并相应地更新了 PENSJA_BR 列。不过,您必须根据需要对其进行更新并添加您需要的额外内容。

DECLARE

check_stauts NUMBER;

    CURSOR kurs IS 
    SELECT id_pracownika, pensja_br, wiek
    FROM pracownicy;

BEGIN
    FOR i IN kurs LOOP
        if i.wiek > 40 THEN
        UPDATE pracownicy
        SET
            pensja_br = i.pensja_br * 1.02
        WHERE
            id_pracownika = i.id_pracownika; 
    END IF;
    END LOOP;
END;

PS:当尝试为变量赋值时:

pensja := PESNJA_BR * 1.02

【讨论】:

    【解决方案3】:

    我认为您可以使用单个更新语句,但您也想打印详细信息。您可以使用FOR 循环如下:

    BEGIN 
    FOR I IN (
        SELECT P.ID_PRACOWNIKA,
               P.PENSJA_BR * 1.02 AS PENSJA_BR
          FROM PRACOWNICY   P
          JOIN OSOBY        O
        ON P.ID_OSOBY = O.ID_OSOBY
         WHERE O.WIEK > 40
    ) LOOP
            UPDATE PRACOWNICY P
               SET P.PENSJA_BR = I.PENSJA_BR
             WHERE P.ID_PRACOWNIKA = I.ID_PRACOWNIKA;
    
            DBMS_OUTPUT.PUT_LINE(I.ID_PRACOWNIKA || '-' || I.PENSJA_BR);
      END LOOP;
    END;
    

    如果您只想使用单个查询更新数据,则可以使用以下更新 SQL:

    UPDATE PRACOWNICY P
       SET P.PENSJA_BR = P.PENSJA_BR * 1.02
     WHERE EXISTS (
        SELECT 1
          FROM OSOBY O
         WHERE P.ID_OSOBY = O.ID_OSOBY
           AND O.WIEK > 40
    );
    

    【讨论】:

    • 非常感谢
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-04-18
    • 1970-01-01
    相关资源
    最近更新 更多