2011-11-07 28 views
2

以下情况:T-SQL触发器,不确定性错误,SQL Server

我们从某个外部来源获取某些呼叫的结算信息。他们只有一个时间戳,主叫方和被叫服务号码。我们必须在我们的数据库中找到一个唯一的ID,以便相应的数据集能够处理数据。

service == msn + ddi 

现在的问题:

下面的SELECT导致如果叫上表中的一个后插入触发器中的不确定性返回NULL。

如果单独调用select总会得到结果,我使用外部数据手动验证。

- >外部数据不是原因!

有什么建议吗?我写了一个SQL脚本来解释功能。你可以运行这个脚本来理解它是如何工作的。

CREATE TABLE [dbo].[table_b] (
    [id] [int] IDENTITY(1,1) NOT NULL, 
    [msn] [varchar](25) NOT NULL, 
    [ddi] [varchar](10) NOT NULL, 
    [caller] [varchar](25) NOT NULL, 
    [timestamp] [datetime] NOT NULL, 
CONSTRAINT [PK_table_b] PRIMARY KEY CLUSTERED 
(
    [id] ASC 
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY] 
) ON [PRIMARY] 
GO 

CREATE TABLE [dbo].[table_a](
    [id] [int] IDENTITY(1,1) NOT NULL, 
    [table_b_id] [int] NULL, 
    [caller] [varchar](25) NOT NULL, 
    [service] [varchar](36) NOT NULL, 
    [call_time] [datetime] NOT NULL, 
CONSTRAINT [PK_table_a] PRIMARY KEY CLUSTERED 
(
    [id] ASC 
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY] 
) ON [PRIMARY] 
GO 

ALTER TABLE [dbo].[table_a] ADD CONSTRAINT [FK_table_a_ref_table_b] FOREIGN KEY([table_b_id]) 
REFERENCES [dbo].[table_b] ([id]) 
ON DELETE SET NULL 
GO 


CREATE TRIGGER [dbo].[On_table_a_after_insert] ON [dbo].[table_a] AFTER INSERT 
AS 
BEGIN 
    SET NOCOUNT ON; 

    DECLARE @inserted CURSOR 
    DECLARE @a_id INT, @caller VARCHAR(25), @service VARCHAR(36), @call_time DATETIME, @error VARCHAR(255) 
    DECLARE @dt_st DATETIME, @dt_end DATETIME, @b_id INT, @msn VARCHAR(25), @ddi VARCHAR(10) 

    SET @inserted = CURSOR FORWARD_ONLY FOR (
     SELECT [id], [caller], [service], [call_time] FROM inserted) 

    OPEN @inserted 

    FETCH NEXT FROM @inserted INTO @a_id, @caller, @service, @call_time 

    WHILE (@@FETCH_STATUS = 0) 
    BEGIN 
     SET @dt_st = DATEADD(SECOND, -15, @call_time) 
     SET @dt_end = DATEADD(SECOND, 15, @call_time) 
     --the timestamp in table b can differ, caused by automatically insertion 
     --through an external software 

     --some error checks if the data is valid 
     --not needed here because I tested the data manually 

     BEGIN TRY 
      --find best matching data from table_b 
      SELECT TOP 1 @b_id=[id], @msn=[msn], @ddi=[ddi] 
      FROM [dbo].[table_b] 
      WHERE [caller] = @caller AND [timestamp] > @dt_st AND [timestamp] < @dt_end AND ([msn] + [ddi]) = SUBSTRING(@service, 1, LEN([msn] + [ddi])) 
      ORDER BY ABS(DATEDIFF(SECOND,[timestamp],@call_time)) ASC 
     END TRY 
     BEGIN CATCH 
      SET @error = 'Failed to retrieve data from [table_b] for table_a ID = ' + CAST(@a_id AS VARCHAR(10)) + '!' 
      RAISERROR (@error,11,1) 
      FETCH NEXT FROM @inserted INTO @a_id, @caller, @service, @call_time 
      CONTINUE 
     END CATCH 
     IF (@b_id IS NULL) 
     BEGIN 
      --sometimes this error is raised (with valid data) 
      SET @error = 'No data found in [table_b] table for table_a ID = ' + CAST(@a_id AS VARCHAR(10)) + '!' 
      RAISERROR (@error,11,1) 
      FETCH NEXT FROM @inserted INTO @a_id, @caller, @service, @call_time 
      CONTINUE 
     END 
     --update the reference 
     UPDATE [dbo].[table_a] 
     SET [table_b_id] = @b_id 
     WHERE [id] = @a_id 

     FETCH NEXT FROM @inserted INTO @a_id, @caller, @service, @call_time 
    END 

    CLOSE @inserted 
    DEALLOCATE @inserted 
END 

INSERT INTO [dbo].[table_b] ([caller],[timestamp],[msn],[ddi]) 
VALUES ('004984199376893','2011-09-01 01:31:21.000','9005778808','8') 
INSERT INTO [dbo].[table_b] ([caller],[timestamp],[msn],[ddi]) 
VALUES ('00494516116143','2011-09-01 08:50:44.000','9005778808','7') 
INSERT INTO [dbo].[table_b] ([caller],[timestamp],[msn],[ddi]) 
VALUES ('004962069090587','2011-09-01 09:25:28.000','9005232464','') 
INSERT INTO [dbo].[table_b] ([caller],[timestamp],[msn],[ddi]) 
VALUES ('004923074387247','2011-09-01 09:32:37.000','9001122567','') 
INSERT INTO [dbo].[table_b] ([caller],[timestamp],[msn],[ddi]) 
VALUES ('004923074387247','2011-09-01 09:48:24.000','9001122567','') 
INSERT INTO [dbo].[table_b] ([caller],[timestamp],[msn],[ddi]) 
VALUES ('004923074387247','2011-09-01 09:50:49.000','9001122567','') 
INSERT INTO [dbo].[table_b] ([caller],[timestamp],[msn],[ddi]) 
VALUES ('00493685704108','2011-09-01 13:30:47.000','9001220774','') 
INSERT INTO [dbo].[table_b] ([caller],[timestamp],[msn],[ddi]) 
VALUES ('004971624629971','2011-09-01 16:04:35.000','9005882230','') 
INSERT INTO [dbo].[table_b] ([caller],[timestamp],[msn],[ddi]) 
VALUES ('004971624629971','2011-09-01 16:11:18.000','9005882230','') 
INSERT INTO [dbo].[table_b] ([caller],[timestamp],[msn],[ddi]) 
VALUES ('004984199376893','2011-09-02 02:14:41.000','9005778808','8') 
--to table a with call_time's difference 
INSERT INTO [dbo].[table_a] ([caller],[service],[call_time]) 
VALUES ('004984199376893','90057788088','2011-09-01 01:31:23.000') 
INSERT INTO [dbo].[table_a] ([caller],[service],[call_time]) 
VALUES ('00494516116143','90057788087','2011-09-01 08:50:46.000') 
INSERT INTO [dbo].[table_a] ([caller],[service],[call_time]) 
VALUES ('004962069090587','9005232464','2011-09-01 09:25:33.000') 
INSERT INTO [dbo].[table_a] ([caller],[service],[call_time]) 
VALUES ('004923074387247','9001122567','2011-09-01 09:32:40.000') 
INSERT INTO [dbo].[table_a] ([caller],[service],[call_time]) 
VALUES ('004923074387247','9001122567','2011-09-01 09:48:28.000') 
INSERT INTO [dbo].[table_a] ([caller],[service],[call_time]) 
VALUES ('004923074387247','9001122567','2011-09-01 09:50:53.000') 
INSERT INTO [dbo].[table_a] ([caller],[service],[call_time]) 
VALUES ('00493685704108','9001220774','2011-09-01 13:30:48.000') 
INSERT INTO [dbo].[table_a] ([caller],[service],[call_time]) 
VALUES ('004971624629971','9005882230','2011-09-01 16:04:39.000') 
INSERT INTO [dbo].[table_a] ([caller],[service],[call_time]) 
VALUES ('004971624629971','9005882230','2011-09-01 16:11:21.000') 
INSERT INTO [dbo].[table_a] ([caller],[service],[call_time]) 
VALUES ('004984199376893','90057788088','2011-09-02 02:14:41.000') 
+0

downvote的原因是什么?有问题? – kockiren

+0

难以遵循。较少描述和更多代码(包括'CREATE TABLE'语句和示例数据)会更好。 –

+3

仍然不明白你在问什么。你是说'@ our_id'是'NULL'?如果是这样,那么'WHERE'子句就不能匹配任何东西。请在“@ call_time” –

回答

3

你可以尝试下面的查询,而不是你的光标:

WITH cte AS (
    SELECT 
    a.id, 
    b_id = b.id, 
    rnk = ROW_NUMBER() OVER (
     PARTITION BY a.id 
     ORDER BY ABS(DATEDIFF(SECOND, timestamp, a.call_time)) ASC 
    ) 
    FROM inserted a 
    INNER JOIN dbo.table_b b 
     ON b.caller = a.caller 
     AND b.timestamp > DATEADD(SECOND, -15, a.call_time) 
     AND b.timestamp < DATEADD(SECOND, +15, a.call_time) 
     AND b.msn + b.ddi = SUBSTRING(a.service, 1, LEN(b.msn + b.ddi)) 
) 
UPDATE dbo.table_a 
SET table_b_id = cte.b_id 
FROM cte 
WHERE cte.id = dbo.table_a.id 
    AND cte.rnk = 1 
; 

也许有什么东西我错过了,但至少,当我测试,此更新产生相同的结果光标定位到触发。

我没有改变你的逻辑太多,但是,事实上,该位

… 
AND b.msn + b.ddi = SUBSTRING(a.service, 1, LEN(b.msn + b.ddi)) 
… 

可能使查询非sargable。我将这个特殊的检查大概分为两个:

… 
AND b.msn = SUBSTRING(a.service, 1,    LEN(b.msn)) 
AND b.ddi = SUBSTRING(a.service, LEN(b.msn) + 1, LEN(b.ddi)) 
… 

有用的书:

+0

thx为您的答案。问题是我们得到错误的数据(格式错误的callerid ...),我们必须纠正它。现在我们纠正插入过程,然后我们不需要触发器。 Thx为您提供帮助。 – kockiren