现在我正在编写一个具有PostgreSQL DB的应用程序。
我的任务是根据new.id
编写将执行SQL语句的触发器。
只有一个问题,即触发器不执行查询。它只是插入任何东西。
CREATE OR REPLACE FUNCTION bill_creator()
RETURNS TRIGGER AS $build_bill$
declare
summ INTEGER;
BEGIN
SELECT SUM(ITEMS.PRICE) INTO summ
FROM ITEMS
INNER JOIN PARTS
ON PARTS.ITEM_ID = ITEMS.ID AND PARTS.ORDER_ID = NEW.ID;
INSERT INTO BILLS (
created,
summary,
cashier_id,
customer_id,
order_id,
created_at,
updated_at,
options
)
VALUES (
current_date,
summ,
1,
new.customer_id,
new_id,
current_timestamp,
current_timestamp,
'None'
);
RETURN NEW;
END;
$build_bill$ LANGUAGE plpgsql;
CREATE OR REPLACE TRIGGER build_bill AFTER INSERT ON ORDERS
FOR EACH ROW EXECUTE PROCEDURE bill_creator();
我正在使用Rails,因此表由ActiveRecords创建,但它们存储在架构中。
create_table "bills", force: :cascade do |t|
t.datetime "created"
t.string "options"
t.integer "summary"
t.integer "cashier_id"
t.integer "customer_id"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.integer "order_id"
end
create_table "orders", force: :cascade do |t|
t.integer "customer_id"
t.integer "waiter_id"
t.integer "manager_id"
t.integer "chef_id"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
end
create_table "parts", force: :cascade do |t|
t.integer "order_id"
t.integer "item_id"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
end
create_table "items", force: :cascade do |t|
t.integer "price"
t.string "description"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.integer "menu_id"
end
add_index "parts", ["item_id"], name: "index_parts_on_item_id", using: :btree
add_index "parts", ["order_id"], name: "index_parts_on_order_id", using: :btree
答案 0 :(得分:1)
你的功能看起来基本上很好。我简化并修复了一些问题:
CREATE OR REPLACE FUNCTION bill_creator()
RETURNS TRIGGER AS
$build_bill$
BEGIN
INSERT INTO bills (
created,
summary,
cashier_id,
customer_id,
order_id,
created_at,
updated_at,
options
)
SELECT
current_date,
SUM(i.price)
1,
NEW.customer_id,
NEW.id -- ! 'new_id was undefined !
current_timestamp,
current_timestamp,
'None'
FROM parts p
JOIN items i ON p.item_id = i.id
WHERE p.order_id = NEW.id;
RETURN NULL;
END
$build_bill$ LANGUAGE plpgsql;
您不需要单独的SELECT和变量赋值。将其集成到单个INSERT
中,速度更快。结果相同,即使找不到任何内容,聚合函数sum()
也总是返回一行。
new_id
未定义,我认为您的意思是NEW.id
?
我使用RETURN NULL
因为per documentation:
始终忽略已触发的行级触发器的返回值
AFTER
[...];它也可能是空的。
不确定为什么你有created
和created_at
。两者都是类型定义的AS t.datetime
,它应转换为Postgres timestamp
。也不确定为什么要将current_date
而不是current_timestamp
写入第一个。
但是,插入的summary
为NULL并不奇怪。在orders
中插入一行后,parts
中不存在相关条目,但假设参照完整性。因此,此时在bill
中插入总和的想法必然会失败。对于插入/更新/删除的每个新UPDATE
,您必须part
该列。这是一袋你必须处理的跳蚤来保持这个总和 - 或多或少......
我建议您完全删除列bill.summary
,然后使用VIEW
代替动态计算总和。可以是MATERIALIZED VIEW
以避免重复聚合。