Oracle PL/SQL中用于在表中插入新记录的存储过程

Oracle PL/SQL中用于在表中插入新记录的存储过程,oracle,plsql,Oracle,Plsql,我需要创建一个PL/SQL存储过程来向tblCity2表中添加一条记录。tblCity2样品: +-------------+--------+-------------+------------+ | NAME | CAPITAL| POPULATION | STATE_CODE | +-------------+--------+-------------+------------+ | Monterrey | Y | 2015000 | MX

我需要创建一个PL/SQL存储过程来向tblCity2表中添加一条记录。tblCity2样品:

+-------------+--------+-------------+------------+
|     NAME    | CAPITAL|  POPULATION | STATE_CODE |
+-------------+--------+-------------+------------+
| Monterrey   |   Y    |   2015000   |      MX19  |
| Mazatlan    |   N    |    199830   |      MX25  |
| Guadalajara |   Y    |   2325000   |      MX14  |
+-------------+--------+-------------+------------+
该过程接收4个参数:城市名称、城市是否为首都、城市人口和州名称。状态名称取自表tblState2:

+------+-----------------------+---------+-----------+
| CODE |         NAME          | POP1990 | AREA_SQMI |
+------+-----------------------+---------+-----------+
| MX02 | Baja California Norte | 1660855 | 28002.325 |
| MX03 | Baja California Sur   |  317764 | 27898.191 |
| MX18 | Nayarit               |  824643 | 10547.762 |
+------+-----------------------+---------+-----------+
该过程调用一个向其传递状态名的存储函数,该函数返回状态代码,然后该代码与其他参数一起用于在tblCity2中插入新记录

我已经开始了一些代码,但我不确定下一步:

PROCEDURE question2
(i_StateName IN TBLSTATE2.NAME%TYPE,
i_CityName IN TBLCITY2.NAME%TYPE,
i_CityCapital IN TBLCITY2.CAPITAL%TYPE,
i_CityPopulation IN TBLCITY2.POPULATION%TYPE);

FUNCTION create_city
(i_StateName IN TBLSTATE2.NAME%TYPE)
RETURN [something??]
INSERT INTO TBLCITY2 VALUES;
END question2;
我还需要插入一个匿名程序块来调用该过程。这是正确的吗?我可以在与上面相同的代码中运行此代码,还是必须单独运行

BEGIN
question2(i_StateName, i_CityName, i_CityCapital, i_CityPopulation);
END;

您可以使用
SELECT。。INTO
语句,以根据州名称获取州代码。
INTO
子句允许您指定存储select语句返回值的变量

FUNCTION getStateCode
  (i_StateName IN TBLSTATE2.NAME%TYPE) 
RETURN tblState2.CODE%TYPE IS
  V_CODE tblState2.CODE%TYPE;
BEGIN
    SELECT CODE
    INTO   V_CODE
    FROM   tblState2
    WHERE  NAME = i_StateName;

    RETURN V_CODE;
END;
请注意,查询必须只返回一行。如果它返回0行或多于1行,它将失败,找不到数据或行太多

通过将查询嵌入从双查询中选择,可以捕获未找到数据错误:

FUNCTION getStateCode
  (i_StateName IN TBLSTATE2.NAME%TYPE) 
RETURN tblState2.CODE%TYPE IS
  V_CODE tblState2.CODE%TYPE;
BEGIN
    SELECT (SELECT CODE
            FROM   tblState2
            WHERE  NAME = i_StateName)
    INTO   V_CODE
    FROM   DUAL

    RETURN V_CODE;
END;
该函数返回代码,然后可在过程的insert语句中使用该代码:

PROCEDURE insertCity
  (i_StateName      IN TBLSTATE2.NAME%TYPE,
   i_CityName       IN TBLCITY2.NAME%TYPE,
   i_CityCapital    IN TBLCITY2.CAPITAL%TYPE,
   i_CityPopulation IN TBLCITY2.POPULATION%TYPE) IS

BEGIN

    INSERT INTO TBLCITY2 (NAME, CAPITAL, POPULATION, STATE_CODE)
    VALUES(
      i_CityName,
      i_CityCapital,
      i_CityPopulation,
      getStateCode(i_StateName)
    );

END;
然后,您可以完全按照如下方式调用该过程:

BEGIN
  insertCity(i_StateName, i_CityName, i_CityCapital, i_CityPopulation);
END;
就像@APC在评论中提到的那样,修改函数内部的数据是一种不好的做法。这样做的原因是,也可以从查询中调用函数,这意味着您可以在只想查询数据时意外地修改数据


因此,在上面的设置中,有一个只查询数据的函数。该函数可以在SQL中使用,也可以(在本例中)在过程中使用。该过程可以安全地修改数据,因为它无论如何都不能用于select查询。

OP需要一个函数来检索查找
状态\u code
,而不是在insert语句中使用标量游标。正如您所知,使用函数更改系统状态被认为是不好的做法(没有双关语)。使用过程的原始实现更好。@APC我同意您关于函数更改状态的看法,我想我只是误解了这个问题。我删除了所有以前的内容并编写了一个新的内容,其中一个函数返回状态名,然后该函数将在过程中使用,而不是在subselect中使用。