overmind 2023-09-30 08:24 采纳率: 92.9%
浏览 8
已结题

关于PROCEDURE和FUNCTION的问题

CREATE TABLE public.bill (
    ic_id character varying(10),
    dk_id character varying(10),
    deal_time timestamp without time zone,
    price numeric
);
CREATE TABLE public.stall (
    dk_id character varying(10),
    shop character varying(20),
    shop_owner character varying(20)
);

COPY public.bill (ic_id, dk_id, deal_time, price) FROM stdin;
ic2034123    dk1000234    2023-09-30 11:30:01    15
ic2052342    dk1001584    2023-09-30 11:33:03    30
ic2034123    dk1001584    2023-09-30 11:34:04    3
ic2033233    dk1003324    2023-09-30 11:36:23    20
ic2035678    dk1000436    2023-09-30 11:36:44    20
ic2034434    dk1001584    2023-09-30 11:37:51    25
ic1034139    dk1003324    2023-09-30 11:38:23    20
\.

COPY public.stall (dk_id, shop, shop_owner) FROM stdin;
dk1000436    饭是钢    胡小喵
dk1000234    兰州拉面    刘老根
dk1003324    煎饼虎头军    胡小喵
dk1001584    老家肉饼    刘老根
\.
  • 上述代码生成两个表
    • bill 表 记录 消费的ic卡、档口id、金额、时间
    • stall 表 记录 档口的具体品牌和老板

img

  • 现在想要插入记录

    • ic1003532,dk1001584,2023-10-01,10:00:00,10,老家肉饼,刘老根
    • 由于刘老根的老家肉饼店铺的dk_id已存在,只插入账单表(bill)
  • 如果有一个新的档口,比如

    • ic1003533,dk1001589,2023-10-01,11:00:00,10,沙县小吃,沙老板
    • 由于新档口 不存在 需要在两个表插入记录
    • 这应该 建立一个FUNCTION 还是 PROCEDURE?
      • 我对于这两者区别 不是很清楚
      • 具体应该怎么写?
  • 删除店铺(stall)记录时,想要制作一个触发器TRIGGER

    • 连带删除所有bill中相关记录
    • 具体应该怎么写?
  • 谢谢指教!

  • 写回答

7条回答 默认 最新

  • 专家-赤兔[在线] 全栈领域优质创作者 2023-09-30 08:29
    关注

    以下回复引自强大而免费的微信小程序:皆我百晓生。如有帮助,还望采纳。


    方法1:
    在这种情况下,可以使用一个FUNCTION来实现插入记录的操作。FUNCTION是一种可以返回值的数据库对象,可以用于执行特定的计算和操作。对于要插入的新档口,可以在函数中使用条件语句来判断该档口是否已存在,如果不存在,则在stall表中插入新记录,并在bill表中插入新的账单记录。如果档口已经存在,则只需要在bill表中插入新的账单记录即可。

    示例代码如下:

    CREATE FUNCTION insert_record(ic_id character varying, dk_id character varying, deal_date date, deal_time time, price numeric, shop character varying, shop_owner character varying)
    RETURNS void AS $$
    BEGIN
        IF NOT EXISTS(SELECT 1 FROM stall WHERE dk_id = dk_id) THEN
            INSERT INTO stall (dk_id, shop, shop_owner)
            VALUES (dk_id, shop, shop_owner);
        END IF;
        
        INSERT INTO bill (ic_id, dk_id, deal_time, price)
        VALUES (ic_id, dk_id, TIMESTAMP deal_date || ' ' || deal_time, price);
    END;
    $$ LANGUAGE plpgsql;
    

    对于删除店铺记录后删除关联的bill记录,可以使用触发器TRIGGER来实现。触发器是一种特殊的数据库对象,可以在表上定义,以在表上的特定操作(如INSERT、DELETE、UPDATE)发生时自动触发。可以在删除店铺记录之前创建一个DELETE触发器,当删除店铺记录时,触发器会在执行删除操作之前删除所有关联的bill记录。

    示例代码如下:

    CREATE FUNCTION delete_related_bills() RETURNS TRIGGER AS $$
    BEGIN
        DELETE FROM bill WHERE dk_id = OLD.dk_id;
        RETURN OLD;
    END;
    $$ LANGUAGE plpgsql;
    
    CREATE TRIGGER delete_related_bills_trigger
    BEFORE DELETE ON stall
    FOR EACH ROW
    EXECUTE FUNCTION delete_related_bills();
    

    通过上述代码,当执行删除店铺记录的操作时,将会触发delete_related_bills_trigger触发器,触发器会在删除店铺记录之前删除所有关联的bill记录。


    方法2:
    对于插入记录的需求,可以使用一个存储过程(PROCEDURE)来实现。存储过程可以执行一系列的 SQL 语句,可以在其中进行必要的条件判断和数据插入操作。

    以下是一个示例存储过程的代码片段,用于根据给定的参数插入数据到 bill 表:

    CREATE OR REPLACE PROCEDURE insert_bill(
         ic_id_val character varying(10),
         dk_id_val character varying(10),
         date_val date,
         time_val time,
         price_val numeric,
         shop_val character varying(20),
         shop_owner_val character varying(20)
    )
    LANGUAGE plpgsql
    AS $$
    BEGIN
         -- 检查档口是否存在
         IF EXISTS (SELECT * FROM stall WHERE dk_id = dk_id_val) THEN
             -- 档口存在,只插入 bill 表
             INSERT INTO bill (ic_id, dk_id, deal_time, price)
             VALUES (ic_id_val, dk_id_val, date_val + time_val, price_val);
         ELSE
             -- 档口不存在,先插入 stall 表,再插入 bill 表
             INSERT INTO stall (dk_id, shop, shop_owner)
             VALUES (dk_id_val, shop_val, shop_owner_val);
       
             INSERT INTO bill (ic_id, dk_id, deal_time, price)
             VALUES (ic_id_val, dk_id_val, date_val + time_val, price_val);
         END IF;
    END;
    $$;
    

    使用该存储过程可以执行以下操作:

    CALL insert_bill('ic1003532', 'dk1001584', '2023-10-01', '10:00:00', 10, '老家肉饼', '刘老根');
    

    对于删除店铺记录并触发连带删除相关的 bill 记录的需求,可以使用触发器(TRIGGER)来实现。

    以下是一个示例触发器的代码片段,用于在删除 stall 表记录时同时删除 bill 表相关记录:

    CREATE OR REPLACE FUNCTION delete_related_bills()
    RETURNS TRIGGER AS $$
    BEGIN
         DELETE FROM bill WHERE dk_id = OLD.dk_id;
         RETURN OLD;
    END;
    $$ LANGUAGE plpgsql;
    
    CREATE TRIGGER delete_related_bills_trigger
    AFTER DELETE ON stall
    FOR EACH ROW
    EXECUTE FUNCTION delete_related_bills();
    

    创建完触发器后,每当删除 stall 表的记录时,相关的 bill 表记录也会被自动删除。

    注意:以上代码只是示例,您需要根据实际的表结构和需求进行适当的调整和修改。还要确保在执行任何更改之前进行适当的备份,以免意外删除了重要的数据。

    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论
查看更多回答(6条)

报告相同问题?

问题事件

  • 系统已结题 10月10日
  • 已采纳回答 10月2日
  • 创建了问题 9月30日

悬赏问题

  • ¥20 wireshark抓不到vlan
  • ¥20 关于#stm32#的问题:需要指导自动酸碱滴定仪的原理图程序代码及仿真
  • ¥20 设计一款异域新娘的视频相亲软件需要哪些技术支持
  • ¥15 stata安慰剂检验作图但是真实值不出现在图上
  • ¥15 c程序不知道为什么得不到结果
  • ¥40 复杂的限制性的商函数处理
  • ¥15 程序不包含适用于入口点的静态Main方法
  • ¥15 素材场景中光线烘焙后灯光失效
  • ¥15 请教一下各位,为什么我这个没有实现模拟点击
  • ¥15 执行 virtuoso 命令后,界面没有,cadence 启动不起来