【发布时间】:2017-11-30 11:18:50
【问题描述】:
我正在尝试设计一个接收订单行的登陆表,然后触发器会将数据发送到适当的表(即客户、订单、订单行)。
我可以在 MySQL 中使用新旧关键字轻松完成此操作,但是我在 SQL Server 中遇到了一些问题。
首先 - 这是解决此类问题的最佳方法吗?
其次,如果是,我尝试创建一个触发器,该触发器使用游标遍历 SQL Server 中插入的表。不幸的是,我不断收到错误
消息 16916,级别 16,状态 1,过程 _raw_b2c_lines_ins,第 17 行 [批处理开始第 6 行]
名为“ins_cusor”的游标不存在
我附上了下面的代码(删除了订单和订单行表的代码以简化)
CREATE OR ALTER TRIGGER zap._raw_b2c_lines_ins
on zap._b2c
after insert
as
begin
declare @v_phone_cleansed varchar
, @phone varchar
, @v_curr_cust_id varchar
, @customer_key varchar
, @t_order_id int
, @customer_id varchar
, @t_raw_id int
--
declare ins_cursor CURSOR FOR SELECT t_raw_id from inserted;
--
OPEN ins_cusor;
FETCH NEXT from ins_cursor INTO @t_raw_id;
WHILE (@@FETCH_STATUS = 0)
--
BEGIN
set @v_phone_cleansed = dbo.CleanNumber((select billing_phone
from inserted
where t_raw_id = @t_raw_id
));
set @v_curr_cust_id = (select isnull(max(t_customer_id),0) +1 from sales.b2c_customer);
--
if exists( select 1
from sales.b2c_customer c
join inserted i
on lower(c.first_name) = lower(i.billing_first_name)
and lower(c.last_name) = lower(i.billing_last_name)
and lower(c.email) = lower(i.billing_email)
and ( lower(c.country) != lower(i.billing_country)
or lower(c.city) != lower(i.billing_city)
or c.phone_cleansed != @v_phone_cleansed
)
and c.current_record = 1
and i.t_raw_id = @t_raw_id )
--
Begin
set @customer_key = ( select top 1 customer_key
from sales.b2c_customer c
join inserted i
on lower(c.first_name) = lower(i.billing_first_name)
and lower(c.last_name) = lower(i.billing_last_name)
and lower(c.email) = lower(i.billing_email)
and ( lower(c.country)!= lower(i.billing_country)
or lower(c.city) != lower(i.billing_city)
or c.phone_cleansed != @v_phone_cleansed
)
and c.current_record = 1
and i.t_raw_id = @t_raw_id
);
--
update sales.b2c_customer
set current_record = 0
where exists (select *
from sales.b2c_customer c
join inserted i
on lower(c.first_name) = lower(i.billing_first_name)
and lower(c.last_name) = lower(i.billing_last_name)
and lower(c.email) = lower(i.billing_email)
and ( lower(c.country) != lower(i.billing_country)
or lower(c.city) != lower(i.billing_city)
or c.phone_cleansed != @v_phone_cleansed
)
and c.current_record = 1
and i.t_raw_id = @t_raw_id
)
insert into sales.b2c_customer(
customer_key
, last_name
, first_name
, email
, country
, city
, phone
, phone_cleansed
, current_record
) select @customer_key
, dbo.InitCap(i.billing_last_name)
, dbo.InitCap(i.billing_first_name)
, i.billing_email
, i.billing_country
, dbo.InitCap(i.billing_city)
, i.billing_phone
, @v_phone_cleansed
, 1
from inserted i
where i.t_raw_id = @t_raw_id
;
--
end
--
if exists( select 1
from sales.b2c_customer c
join inserted i
on lower(c.first_name) = lower(i.billing_first_name)
and lower(c.last_name) = lower(i.billing_last_name)
and lower(c.email) != lower(i.billing_email)
and lower(c.country) = lower(i.billing_country)
and lower(c.city) = lower(i.billing_city)
and lower(c.phone_cleansed) = @v_phone_cleansed
and current_record = 1
and i.t_raw_id = @t_raw_id
)
--
Begin
--
set @customer_key = ( select top 1 customer_key
from sales.b2c_customer c
join inserted i
on lower(c.first_name) = lower(i.billing_first_name)
and lower(c.last_name) = lower(i.billing_last_name)
and lower(c.email) != lower(i.billing_email)
and lower(c.country) = lower(i.billing_country)
and lower(c.city) = lower(i.billing_city)
and c.phone_cleansed = @v_phone_cleansed
and i.t_raw_id = @t_raw_id
);
update sales.b2c_customer
set current_record = 0
where exists (select *
from sales.b2c_customer c
join inserted i
on lower(c.first_name) = lower(i.billing_first_name)
and lower(c.last_name) = lower(i.billing_last_name)
and lower(c.email) != lower(i.billing_email)
and lower(c.country) = lower(i.billing_country)
and lower(c.city) = lower(i.billing_city)
and c.phone_cleansed = @v_phone_cleansed
and c.current_record = 1
and i.t_raw_id = @t_raw_id
)
insert into sales.b2c_customer(
customer_key
, last_name
, first_name
, email
, country
, city
, phone
, phone_cleansed
, current_record
) select @customer_key
, dbo.InitCap(i.billing_last_name)
, dbo.InitCap(i.billing_first_name)
, i.billing_email
, i.billing_country
, dbo.InitCap(i.billing_city)
, i.billing_phone
, @v_phone_cleansed
, 1
from inserted i
where i.t_raw_id = @t_raw_id
--
end
--
if not exists (
select 1
from sales.b2c_customer c
join inserted i
on lower(c.first_name) = lower(i.billing_first_name)
and lower(c.last_name) = lower(i.billing_last_name)
and lower(c.email) = lower(i.billing_email)
and lower(c.country) = lower(i.billing_country)
and lower(c.city) = lower(i.billing_city)
and c.phone_cleansed = @v_phone_cleansed
and c.current_record = 1
and i.t_raw_id = @t_raw_id
)
--
Begin
--
insert into sales.b2c_customer( customer_key
, last_name
, first_name
, email
, country
, city
, phone
, phone_cleansed
, current_record
) select concat(lower(i.billing_first_name), lower(i.billing_last_name), @v_curr_cust_id)
, dbo.InitCap(i.billing_last_name)
, dbo.InitCap(i.billing_first_name)
, i.billing_email
, i.billing_country
, dbo.InitCap(i.billing_city)
, i.billing_phone
, @v_phone_cleansed
, 1
from inserted i
where i.t_raw_id = @t_raw_id;
--
end
--
FETCH NEXT from ins_cursor INTO @t_raw_id;
end
close ins_cursor;
deallocate ins_cursor;
end
【问题讨论】:
-
所以我发现了拼写错误...这就是为什么我会收到错误...我对第一个问题的任何错误都是错误的?是我想要实现的最佳方法吗?
-
输入
OPEN ins_cursor;而不是OPEN ins_cusor; -
Bad habits to kick : declaring VARCHAR without (length) - 您应该始终为您使用的任何
varchar变量和参数提供长度。否则,您最终会得到只有一个字符长的 SQL 变量——通常不是您想要的..... -
哦,我的,光标在触发器中!为什么需要遍历行?你可以使用
inserted来合并你需要的表。 -
这是最好的方法吗?如果不充分了解您的架构以及导致您使用此“解决方案”的原因,那么这个问题就无法准确评估。顺便说一句,我会说不。但这是一个纯粹的猜测。并且在 sql server 中编写触发器很困难 - 这对于那些没有 tsql 经验且没有正确心态的人来说不是什么事情。 sql server 中的触发器以批处理级别执行,并且必须处理由触发 statememt 生成的任意数量的行。
标签: sql-server triggers cursor