簡體   English   中英

使用 PLSQL 創建過程

[英]Creating a procedure with PLSQL

我正在嘗試編寫一個 PLSQL 函數來實現一個約束,即員工不能同時是司機和機械師,換句話說,來自 TRKEMPLOYEE 的相同 E# 不能同時在 TRKDRIVER 和 TRKMECHANIC 中。 如果 DB 的內容違反了該約束,則列出所有既是機械師又是司機的員工的 E# 和 NAME。 上述表格如下所示:

TRKEMPLOYEE(E#              NUMBER(12)      NOT NULL
    NAME            VARCHAR(50)     NOT NULL,
    DOB             DATE                    ,
    ADDRESS         VARCHAR(300)    NOT NULL,
    HIREDATE        DATE            NOT NULL,
CONSTRAINT TRKEMPLOYEE_PKEY PRIMARY KEY(E#))

TRKDRIVER(E#              NUMBER(12)      NOT NULL
L#              NUMBER(8)       NOT NULL,
STATUS          VARCHAR(10)     NOT NULL,
CONSTRAINT TRKDRIVER_PKEY PRIMARY KEY(E#),
CONSTRAINT TRKDRIVER_FKEY FOREIGN KEY(E#) REFERENCES TRKEMPLOYEE(E#))

TRKMECHANIC(E#              NUMBER(12)      NOT NULL
L#              NUMBER(8)       NOT NULL,
STATUS          VARCHAR(10)     NOT NULL,
EXPERIENCE      VARCHAR(10)     NOT NULL,
CONSTRAINT TRKMECHANIC_PKEY PRIMARY KEY(E#),
CONSTRAINT TRKMECHANIC_FKEY FOREIGN KEY(E#) REFERENCES TRKEMPLOYEE(E#))

我試圖編寫一個函數,但在第 1 行第 7 列中不斷出現編譯錯誤。有人能告訴我為什么我的代碼不起作用嗎? 我的代碼如下

CREATE OR REPLACE FUNCTION Verify()
IS DECLARE
  E# TRKEMPLOYEE.E#%TYPE;
  CURSOR C1 IS SELECT E# FROM TRKEMPLOYEE;
BEGIN
  OPEN C1;
  LOOP
   FETCH C1 INTO EMPNUM;
   IF(EMPNUM IN(SELECT E# FROM TRKMECHANIC )AND EMPNUM IN(SELECT E# FROM TRKDRIVER))
     SELECT E#, NAME FROM TRKEMPLOYEE WHERE E#=EMPNUM;
   ELSE
     dbms_output.put_line(“OK”);
   ENDIF
   EXIT WHEN C1%NOTFOUND;
  END LOOP;
  CLOSE C1;
END;
/

任何幫助,將不勝感激。 謝謝。

您正在創建一個函數,但缺少RETURN聲明。 如果您不想返回結果,請使用create or replace procedure

此外,如果您沒有任何參數,請刪除括號()並且DECLARE關鍵字也不正確。


您檢查表格的方式並不是很有效。 您可以通過一個查詢獲得所有違反業務約束的員工的數量:

select emp.e#, 
       emp.name,
       count(drv.e#) + count(mec.e#) as cnt
from trkemployee emp
   left join trkdriver drv on drv.e# = emp.e#
   left join trkmechanic mec on mec.e# = emp.e#
group by emp.e#, emp.name
having count(drv.e#) + count(mec.e#) > 1;

另外EXIT WHEN C1%NOTFOUND; 應該是右FETCH語句。 否則,即使光標沒有獲取任何內容,您仍將停留在循環中。

如果您采用我的簡化語句,您可以循環遍歷所有員工並根據計數打印 OK 或 Not OK:

CREATE OR REPLACE procedure Verify
IS 
  empnum number(12);
  cnt    integer;
  empname varchar(50);

  CURSOR C1 IS 
      select emp.e#,
             emp.name,
             count(drv.e#) + count(mec.e#) as cnt  
      from trkemployee emp
         left join trkdriver drv on drv.e# = emp.e#
         left join trkmechanic mec on mec.e# = emp.e#
      group by emp.e#, emp.name;
BEGIN
  OPEN C1;
  LOOP
    FETCH C1 INTO empnum, empname, cnt;
    EXIT WHEN C1%NOTFOUND;

    if cnt > 1 then 
       dbms_output.put_line(to_char(empnum)||' NOK');
    else
       dbms_output.put_line(to_char(empnum)||' OK');
    end if;

  END LOOP;
CLOSE C1;
END;
/

不用存儲過程解決問題

我正在考慮如何僅通過數據庫中的約束來強制執行此業務規則:

create table trkemployee
(
    E#              NUMBER(12)      NOT NULL,
    NAME            VARCHAR(50)     NOT NULL,
    DOB             DATE                    ,
    ADDRESS         VARCHAR(300)    NOT NULL,
    HIREDATE        DATE            NOT NULL,
    emp_type        char(1)         NOT NULL,
    constraint trkemployee_pkey primary key(e#, emp_type),
    constraint chk_emp_type check (emp_type in ('d','m'))
);

create table TRKDRIVER
(
  e#              number(12)      not null,
  emp_type        char(1)         default 'd' not null,
  l#              number(8)       not null,
  status          varchar(10)     not null,
  constraint trkdriver_pkey primary key(e#),
  constraint trkdriver_fkey foreign key(e#,emp_type) references trkemployee(e#, emp_type),
  constraint check_drv_type check (emp_type = 'd')
);

create table trkmechanic
(
  e#              number(12)      not null,
  emp_type        char(1)         default 'm' not null,
  l#              number(8)       not null,
  status          varchar(10)     not null,
  experience      varchar(10)     not null,
  constraint trkmechanic_pkey primary key(e#),
  constraint trkmechanic_fkey foreign key(e#,emp_type) references trkemployee(e#, emp_type),
  constraint check_mec_type check (emp_type = 'm')
);

這個想法是在其外鍵中包含員工類型,並確保從屬表不能使用錯誤的類型。 插入新的 trkemployee 時,必須指定類型。 詳細表上的檢查約束將拒絕任何類型錯誤的行。

要將員工從一種類型“移動”到另一種類型(如果可能的話),必須首先刪除舊的詳細信息行。 只有這樣,員工的類型才能更改為其他類型。 最后可以插入新的細節。

好吧,這個功能有很多問題。

正如 a_horse_with_no_name 指出的那樣,如果您沒有參數,則刪除()並且根據定義,函數需要 RETURN 語句。

然而,這還不是全部:

  1. 不能在 IF 語句中使用 SELECT。
  2. 您必須將結果放入變量中或將其作為游標的一部分進行引用。
  3. 函數或過程中不需要 DECLARE 塊。
  4. 您的 IF 語句需要 THEN ... 但是,我認為您不需要這個,因為您只是在 ELSE 中做某事。
  5. 您正在將游標的結果提取到一個不存在的變量中。

我會冒險猜測您想要一個程序,因為我不知道您可以返回什么。 我也猜想,如果您不想對第一個 IF 做任何事情,那么您可以將其他選擇放入光標中。

最后,我將假設您將要檢查的員工的e#傳遞給它。

由於所有 3 個表在e#上都是唯一的,因此您可以使用 LEFT OUTER JOINS 將所有 SQL 放在單個游標中

create or replace function verify ( Pemployee trkemployee.e#%type 
            ) return varchar2 is

   l_mechanic trkemployee.e#%type;
   l_driver  trkemployee.e#%type;

begin

   -- Doing things in SQL is more efficient.
    select m.e#, d.e#
      into l_mechanic, l_driver
      from trkemployee e
      left outer join trkmechanic m
        on e.e# = m.e#
      left outer join trkdriver d
        on e.e# = d.e#
           ;

   if l_driver is not null and l_mechanic is not null then
      return 'BAD';
   else
      return 'OK';
   end if;

end;
/

混合a_horse_with_no_nameBen給出的答案,然后“簡化”一點點給出-

CREATE OR REPLACE FUNCTION Verify
 return varchar2 IS                
BEGIN       
  FOR c_rec in (select emp.e#,
                      count(drv.e#) + count(mec.e#) as cnt  
                 from trkemployee emp
                 left join trkdriver drv on drv.e# = emp.e#
                 left join trkmechanic mec on mec.e# = emp.e#
                 group by emp.e#)
   LOOP
    if c_rec.cnt > 1 then 
       return ('BAD '||c_rec.e#);
    else
       return ('OK '||c_rec.e#);
    end if;    
  END LOOP;
EXCEPTION
  WHEN ....THEN
  --as the wise man once said "Do some meaningful exception handling here"...
END;
/

必須DECLAREOPENFETCHCLOSE游標看起來有點矯枉過正。

或者像這樣的PROCEDURE

CREATE OR REPLACE PROCEDURE Verify
IS                
BEGIN       
  FOR c_rec in (select emp.e#,
                      count(drv.e#) + count(mec.e#) as cnt  
                 from trkemployee emp
                 left join trkdriver drv on drv.e# = emp.e#
                 left join trkmechanic mec on mec.e# = emp.e#
                 group by emp.e#)
   LOOP
    if c_rec.cnt > 1 then 
       dbms_output.put_line('BAD '||c_rec.e#);
    else
       dbms_output.put_line('OK '||c_rec.e#);
    end if;    
  END LOOP;
EXCEPTION
  WHEN ....THEN
  --as the wise man once said "Do some meaningful exception handling here"...
END;
/

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM