从 SQL 服务器触发器调用 Freshdesk API
Calling Freshdesk API from a SQL Server trigger
我的客户想要在他的订单 table(来自 Sage)上插入触发器,以使用 API.
创建 Freshdesk 票证
作为我开发的一部分,我构建了一个存储过程,在提供订单号时可以很好地完成工作。但是,将相同的代码移植到触发器中 returns 没有错误,但是当相同的代码在存储过程中工作时,Freshdesk 系统中什么也没有出现。
我期待关于为什么在触发器中调用 API 可能不是一个好主意的评论,但 Freshdesk 调用非常快(从存储过程开始不到 1 秒)。
我想知道的是 -- SQL 服务器是否出于某种原因在架构上禁止这样做?如果允许,我可以在哪里查找抛出的错误。
Edit2:好的,这是整个触发器..之前的版本只有 OA 调用。
ALTER TRIGGER [dbo].[CreateFreshdeskTicketFromOrder]
ON [dbo].[OEORDH]
AFTER INSERT
AS
BEGIN
-- SET NOCOUNT ON added to prevent extra result sets from
-- interfering with SELECT statements.
SET NOCOUNT ON;
-- Get the original order number, and use that in the main lookup query
DECLARE @ORDNUM VARCHAR(22)
SELECT @ORDNUM = ORDNUMBER FROM inserted
-- Variables for fields going to the API
DECLARE @EMAIL VARCHAR(60), @SHPCONTACT VARCHAR(60), @ORDNUMBER VARCHAR(22)
DECLARE @LOCATION VARCHAR(6), @EXPDATE INT
DECLARE @SHPPHONEC VARCHAR(30), @SHPNAME VARCHAR(60), @DESCR VARCHAR(60)
DECLARE @CODEEMPL VARCHAR(15)
-- Collect field values that were just inserted
SELECT
@EMAIL = rtrim(OEORDH1.SHPEMAILC), @SHPCONTACT = rtrim(SHPCONTACT),
@ORDNUMBER = rtrim(ORDNUMBER), @LOCATION = LOCATION, @EXPDATE = EXPDATE,
@SHPPHONEC = rtrim(OEORDH1.SHPPHONEC), @SHPNAME = SHPNAME,
@DESCR = rtrim([DESC]), @CODEEMPL = rtrim(ARSAP.CODEEMPL)
-- FROM inserted
FROM dbo.OEORDH
JOIN dbo.OEORDH1 on dbo.OEORDH.ORDUNIQ = dbo.OEORDH1.ORDUNIQ
JOIN dbo.ARSAP on dbo.OEORDH.SALESPER1 = dbo.ARSAP.CODESLSP
WHERE ORDNUMBER = @ORDNUM
-- Variables from database to the API call
DECLARE @EXPDATE_OUT VARCHAR(10)
SET @EXPDATE_OUT =
substring ( cast ( @EXPDATE as varchar(8) ), 1, 4 ) + '-' +
substring ( cast ( @EXPDATE as varchar(8) ), 5, 2 ) + '-' +
substring ( cast ( @EXPDATE as varchar(8) ), 7, 2 );
DECLARE @STATUS_OUT VARCHAR(2)
IF @LOCATION = '1A'
SET @STATUS_OUT = '23';
ELSE
IF @LOCATION = '1'
SET @STATUS_OUT = '40';
ELSE
SET @STATUS_OUT = '2';
-- Variables for building the API call
DECLARE @Object INT
DECLARE @Url VARCHAR(80)
DECLARE @Body1 VARCHAR(1000) =
'{ ' +
'"email": "'+ @EMAIL +'", ' +
'"custom_fields": { "order_number": "'+ @ORDNUMBER +'", "scheduled_date": "'+ @EXPDATE_OUT + '", ' +
'"delivered_to": "'+ @SHPCONTACT + '", ' + '"consignee_phone_number": "'+ @SHPPHONEC +'" }, ' +
'"status": '+ @STATUS_OUT + ', ' +
'"priority": 1, "subject": "'+ rtrim(@ORDNUMBER) + ' - ' + rtrim(@SHPNAME) + ' (' + @DESCR + ')", ' +
'"responder_id": ' + @CODEEMPL +
' }'
DECLARE @ResponseText VARCHAR(1000), @return_status INT
SET @Url = 'https://client.freshdesk.com/api/v2/tickets';
-- Do REST call to API / All return statuses commented out except for last
Exec @return_status = sp_OACreate 'MSXML2.ServerXMLHTTP', @Object OUT;
-- Select 'Create return', @return_status
Exec @return_status = sp_OAMethod @Object, 'Open', NULL, 'POST', @Url, false
-- Select 'Open return', @return_status
Exec @return_status = sp_OAMethod @Object, 'setRequestHeader', NULL,
'Content-Type', 'application/json'
-- Select 'Set Request Header1 return', @return_status
Exec @return_status = sp_OAMethod @Object, 'setRequestHeader', NULL,
'Authorization', 'Basic ABC123=='
-- Select 'Set Request Header2 return', @return_status
Exec @return_status = sp_OAMethod @Object, 'Send', NULL, @Body1
-- Select 'Send1 return', @return_status
Exec sp_OAMethod @Object, 'ResponseText', @ResponseText OUT
-- Select 'Response', @ResponseText
Exec sp_OADestroy @Object
-- Add the conversation to the TriggerLog
IF @ResponseText IS NULL
SET @ResponseText = '(Null)';
INSERT INTO dbo.TriggerLog (tl_source, tl_input, tl_output) VALUES
( 'FreshdeskInsertTrigger', @Body1, @ResponseText )
END
这是触发代码。
具有相同代码(但将订单号作为参数)的存储过程正常工作并执行 API 调用并进行日志记录。在触发器末尾注释掉日志记录使 Sage 的错误消失,但 API 调用仍然没有到达。
如果您只是从触发器调用工作存储过程(通过 EXEC
)而不是将过程的代码包含在触发器中,会发生什么情况?
需要仔细观察的是代码中的这个地方:
-- Collect field values that were just inserted
SELECT
@EMAIL = rtrim(OEORDH1.SHPEMAILC), @SHPCONTACT = rtrim(SHPCONTACT),
@ORDNUMBER = rtrim(ORDNUMBER), @LOCATION = LOCATION, @EXPDATE = EXPDATE,
@SHPPHONEC = rtrim(OEORDH1.SHPPHONEC), @SHPNAME = SHPNAME,
@DESCR = rtrim([DESC]), @CODEEMPL = rtrim(ARSAP.CODEEMPL)
-- FROM inserted
FROM dbo.OEORDH
JOIN dbo.OEORDH1 on dbo.OEORDH.ORDUNIQ = dbo.OEORDH1.ORDUNIQ
JOIN dbo.ARSAP on dbo.OEORDH.SALESPER1 = dbo.ARSAP.CODESLSP
WHERE ORDNUMBER = @ORDNUM
您注释掉 FROM inserted
并尝试直接从 table 中读取值。
当触发器代码运行时,事务尚未提交,因此您很可能应该从 inserted
table 中读取值。很可能这个 SELECT
没有找到给定 @ORDNUM
的行并且变量仍然是 NULL
.
旁注。 SQL 服务器中的触发器每条语句触发一次,而不是每行一次。即使 inserted
table 有几行,您的触发器也应该正常工作。现在,即使在 table 中插入了多行,您的触发器也只会选择一个 ORDNUMBER
。这很可能不是您想要的。
如何调试触发器?
一种简单且非常 straight-forward 的方法是创建一个 table 用于记录并添加大量 INSERT
语句,将所有变量的值记录到 table .然后您可以阅读日志并查看发生了什么。
我的客户想要在他的订单 table(来自 Sage)上插入触发器,以使用 API.
创建 Freshdesk 票证作为我开发的一部分,我构建了一个存储过程,在提供订单号时可以很好地完成工作。但是,将相同的代码移植到触发器中 returns 没有错误,但是当相同的代码在存储过程中工作时,Freshdesk 系统中什么也没有出现。
我期待关于为什么在触发器中调用 API 可能不是一个好主意的评论,但 Freshdesk 调用非常快(从存储过程开始不到 1 秒)。
我想知道的是 -- SQL 服务器是否出于某种原因在架构上禁止这样做?如果允许,我可以在哪里查找抛出的错误。
Edit2:好的,这是整个触发器..之前的版本只有 OA 调用。
ALTER TRIGGER [dbo].[CreateFreshdeskTicketFromOrder]
ON [dbo].[OEORDH]
AFTER INSERT
AS
BEGIN
-- SET NOCOUNT ON added to prevent extra result sets from
-- interfering with SELECT statements.
SET NOCOUNT ON;
-- Get the original order number, and use that in the main lookup query
DECLARE @ORDNUM VARCHAR(22)
SELECT @ORDNUM = ORDNUMBER FROM inserted
-- Variables for fields going to the API
DECLARE @EMAIL VARCHAR(60), @SHPCONTACT VARCHAR(60), @ORDNUMBER VARCHAR(22)
DECLARE @LOCATION VARCHAR(6), @EXPDATE INT
DECLARE @SHPPHONEC VARCHAR(30), @SHPNAME VARCHAR(60), @DESCR VARCHAR(60)
DECLARE @CODEEMPL VARCHAR(15)
-- Collect field values that were just inserted
SELECT
@EMAIL = rtrim(OEORDH1.SHPEMAILC), @SHPCONTACT = rtrim(SHPCONTACT),
@ORDNUMBER = rtrim(ORDNUMBER), @LOCATION = LOCATION, @EXPDATE = EXPDATE,
@SHPPHONEC = rtrim(OEORDH1.SHPPHONEC), @SHPNAME = SHPNAME,
@DESCR = rtrim([DESC]), @CODEEMPL = rtrim(ARSAP.CODEEMPL)
-- FROM inserted
FROM dbo.OEORDH
JOIN dbo.OEORDH1 on dbo.OEORDH.ORDUNIQ = dbo.OEORDH1.ORDUNIQ
JOIN dbo.ARSAP on dbo.OEORDH.SALESPER1 = dbo.ARSAP.CODESLSP
WHERE ORDNUMBER = @ORDNUM
-- Variables from database to the API call
DECLARE @EXPDATE_OUT VARCHAR(10)
SET @EXPDATE_OUT =
substring ( cast ( @EXPDATE as varchar(8) ), 1, 4 ) + '-' +
substring ( cast ( @EXPDATE as varchar(8) ), 5, 2 ) + '-' +
substring ( cast ( @EXPDATE as varchar(8) ), 7, 2 );
DECLARE @STATUS_OUT VARCHAR(2)
IF @LOCATION = '1A'
SET @STATUS_OUT = '23';
ELSE
IF @LOCATION = '1'
SET @STATUS_OUT = '40';
ELSE
SET @STATUS_OUT = '2';
-- Variables for building the API call
DECLARE @Object INT
DECLARE @Url VARCHAR(80)
DECLARE @Body1 VARCHAR(1000) =
'{ ' +
'"email": "'+ @EMAIL +'", ' +
'"custom_fields": { "order_number": "'+ @ORDNUMBER +'", "scheduled_date": "'+ @EXPDATE_OUT + '", ' +
'"delivered_to": "'+ @SHPCONTACT + '", ' + '"consignee_phone_number": "'+ @SHPPHONEC +'" }, ' +
'"status": '+ @STATUS_OUT + ', ' +
'"priority": 1, "subject": "'+ rtrim(@ORDNUMBER) + ' - ' + rtrim(@SHPNAME) + ' (' + @DESCR + ')", ' +
'"responder_id": ' + @CODEEMPL +
' }'
DECLARE @ResponseText VARCHAR(1000), @return_status INT
SET @Url = 'https://client.freshdesk.com/api/v2/tickets';
-- Do REST call to API / All return statuses commented out except for last
Exec @return_status = sp_OACreate 'MSXML2.ServerXMLHTTP', @Object OUT;
-- Select 'Create return', @return_status
Exec @return_status = sp_OAMethod @Object, 'Open', NULL, 'POST', @Url, false
-- Select 'Open return', @return_status
Exec @return_status = sp_OAMethod @Object, 'setRequestHeader', NULL,
'Content-Type', 'application/json'
-- Select 'Set Request Header1 return', @return_status
Exec @return_status = sp_OAMethod @Object, 'setRequestHeader', NULL,
'Authorization', 'Basic ABC123=='
-- Select 'Set Request Header2 return', @return_status
Exec @return_status = sp_OAMethod @Object, 'Send', NULL, @Body1
-- Select 'Send1 return', @return_status
Exec sp_OAMethod @Object, 'ResponseText', @ResponseText OUT
-- Select 'Response', @ResponseText
Exec sp_OADestroy @Object
-- Add the conversation to the TriggerLog
IF @ResponseText IS NULL
SET @ResponseText = '(Null)';
INSERT INTO dbo.TriggerLog (tl_source, tl_input, tl_output) VALUES
( 'FreshdeskInsertTrigger', @Body1, @ResponseText )
END
这是触发代码。
具有相同代码(但将订单号作为参数)的存储过程正常工作并执行 API 调用并进行日志记录。在触发器末尾注释掉日志记录使 Sage 的错误消失,但 API 调用仍然没有到达。
如果您只是从触发器调用工作存储过程(通过 EXEC
)而不是将过程的代码包含在触发器中,会发生什么情况?
需要仔细观察的是代码中的这个地方:
-- Collect field values that were just inserted
SELECT
@EMAIL = rtrim(OEORDH1.SHPEMAILC), @SHPCONTACT = rtrim(SHPCONTACT),
@ORDNUMBER = rtrim(ORDNUMBER), @LOCATION = LOCATION, @EXPDATE = EXPDATE,
@SHPPHONEC = rtrim(OEORDH1.SHPPHONEC), @SHPNAME = SHPNAME,
@DESCR = rtrim([DESC]), @CODEEMPL = rtrim(ARSAP.CODEEMPL)
-- FROM inserted
FROM dbo.OEORDH
JOIN dbo.OEORDH1 on dbo.OEORDH.ORDUNIQ = dbo.OEORDH1.ORDUNIQ
JOIN dbo.ARSAP on dbo.OEORDH.SALESPER1 = dbo.ARSAP.CODESLSP
WHERE ORDNUMBER = @ORDNUM
您注释掉 FROM inserted
并尝试直接从 table 中读取值。
当触发器代码运行时,事务尚未提交,因此您很可能应该从 inserted
table 中读取值。很可能这个 SELECT
没有找到给定 @ORDNUM
的行并且变量仍然是 NULL
.
旁注。 SQL 服务器中的触发器每条语句触发一次,而不是每行一次。即使 inserted
table 有几行,您的触发器也应该正常工作。现在,即使在 table 中插入了多行,您的触发器也只会选择一个 ORDNUMBER
。这很可能不是您想要的。
如何调试触发器?
一种简单且非常 straight-forward 的方法是创建一个 table 用于记录并添加大量 INSERT
语句,将所有变量的值记录到 table .然后您可以阅读日志并查看发生了什么。