Firebird 有 calculated fields (generated always as/computed by),它们允许从其他表中进行选择(与此答案的早期版本相反,它声明 Firebird 不支持此功能)。
但是,我建议您改用视图,因为我认为它的性能更好(尚未对此进行验证,因此如果性能很重要,我建议您测试一下)。
使用视图
常见的方法是定义一个基表和一个随附的view,在查询时收集必要的数据。人们会从视图中查询,而不是使用基表。
create view order_with_customer
as
select orders.id, orders.customer_id, customer.name
from orders
inner join customer on customer.id = orders.customer_id;
或者您可以跳过视图并在您自己的查询中使用上述连接。
替代方案:计算字段
我将其标记为替代方案而非主要解决方案,因为我认为使用视图将是更可取的解决方案。
要使用计算字段,您可以使用以下语法(注意查询周围的双括号):
create table orders (
id integer generated by default as identity primary key,
customer_id integer not null references customer(id),
customer_name generated always as ((select name from customer where id = customer_id))
)
customer 表的更新将自动反映在orders 表中。
据我所知,此选项的性能低于使用连接时(如视图示例中所用),但您可能想自己测试一下。
带功能的FB3+
使用 Firebird 3,您还可以使用触发器创建计算字段,这使得表达式本身更短。
为此,请创建一个从客户表中选择的function:
create function lookup_customer_name(customer_id integer)
returns varchar(50)
as
begin
return (select name from customer where id = :customer_id);
end
然后创建表为:
create table orders (
id integer generated by default as identity primary key,
customer_id integer not null references customer(id),
customer_name generated always as (lookup_customer_name(customer_id))
);
customer 表的更新将自动反映在orders 表中。选择大量记录时,此解决方案可以相对较慢,因为该功能将单独为每行执行,这比执行连接效率较低。
替代方案:使用触发器
但是,如果您想在插入(或更新)时使用来自另一个表的信息来更新该表,您可以使用 trigger。
我将使用 Firebird 3 作为我的答案,但它也应该翻译成早期版本(有一些细微差别)。
所以假设一个表customer:
create table customer (
id integer generated by default as identity primary key,
name varchar(50) not null
);
带有样本数据:
insert into customer(name) values ('name1');
insert into customer(name) values ('name2');
还有一张桌子orders:
create table orders (
id integer generated by default as identity primary key,
customer_id integer not null references customer(id),
customer_name varchar(50) not null
)
然后定义一个触发器:
create trigger orders_bi_bu
active before insert or update
on orders
as
begin
new.customer_name = (select name from customer where id = new.customer_id);
end
现在当我们使用:
insert into orders(customer_id) values (1);
结果是:
id customer_id customer_name
1 1 name1
更新:
update orders set customer_id = 2 where id = 1;
结果:
id customer_id customer_name
1 2 name2
触发器的缺点是更新customer 表中的名称不会自动反映在orders 表中。您需要自己跟踪这些依赖关系,并在 customer 上创建更新后触发器来更新依赖记录,这可能导致更新/锁定冲突。