为什么这个SQL代码偶尔会产生孤立的记录?

时间:2017-12-28 00:47:11

标签: sql-server database tsql duplicates orphan

免责声明:我不是SQL专家。我想在将记录插入父表之前将其插入子表中。 (在说我开始怀疑这是否是一个好主意之后。)父表记录包含对子表记录的引用,并且所述引用不能为空。这需要我先插入子表,然后在辅助插入期间链接到父表。

无论如何,由于某些原因,此代码在IdentifyingData(子)表中随机生成孤立记录,例如,他们在FraudScore(父)表中没有条目,即使它们应该。

这就是为什么我很困惑。在尝试解决此问题时,我开始将@tempFraudScore表的内容转储到物理审计表中,以便我可以确切地看到数据转换期间发生了什么。当我从@tempFraudScore切换插入FraudScore的以下代码到审计表中插入时,所有子记录都成功获得创建的父记录。这对我来说毫无意义。

insert into IdentifyingData (EntryDateTime, IdentifyingDataTypeId, Value, Source)
select distinct GETDATE(), tfs.IdentifyingDataTypeId, tfs.Value, 'SSIS'
from @tempFraudScore tfs
where not exists (
    select id.IdentifyingDataTypeId, id.Value
    from IdentifyingData id
    where tfs.IdentifyingDataTypeId = id.IdentifyingDataTypeId
        and tfs.Value = id.Value
);

update tfs
set tfs.IdentifyingDataId = id.Id
from @tempFraudScore tfs
    inner join IdentifyingData id on
        tfs.Value = id.Value and
        tfs.IdentifyingDataTypeId = id.IdentifyingDataTypeId;

insert into FraudScore (EntryDateTime, FraudCriteriaId, AccountId, IdentifyingDataId, Score, Source)
select distinct
    GETDATE() EntryDateTime,
    tfs.FraudCriteriaId,
    tfs.AccountId,
    tfs.IdentifyingDataId,
    tfs.Score,
    'SSIS'
from @tempFraudScore tfs
    inner join FraudCriteria fc on
        tfs.FraudCriteriaId = fc.Id
            and fc.UniqueEntryPeriod = 0
where not exists (
    select fs.AccountId, fs.FraudCriteriaId, fs.IdentifyingDataId
    from FraudScore fs
    where tfs.AccountId = fs.AccountId
        and tfs.FraudCriteriaId = fs.FraudCriteriaId
        and tfs.IdentifyingDataId = fs.IdentifyingDataId
);

@tempFraudScore预先填充了除IdentifyingDataId之外的所有必要字段;必须首先插入IdentifyingData,然后使用创建的ID更新变量表。下面是变量表的结构:

declare @tempFraudScore table(
    FraudCriteriaId int,
    AccountId bigint,
    IdentifyingDataId bigint,
    IdentifyingDataTypeId smallint,
    Value varchar(100),
    Score int
);

有人可以告诉我可能导致这些孤立的IdentifyingData记录的原因吗?我应该重新考虑这两个表之间的关系是如何构建的吗?我正在尝试做一些事情,以便一旦某个IdentifyingData记录被放入系统,它就不会重复;它只会被新创建的FraudScore记录引用。

修改 附件是审计表中的屏幕截图,显示了单个值的数据转换进度(值列对于这些记录是相同的值;我为了隐私而模糊了它)。请注意,尽管有消息“Post-FraudScore Insert”,但有问题的记录实际上从未插入到FraudScore表中。

enter image description here

Edit2(2/6/2018):我在尝试解决此问题时已将以下代码添加到存储过程中。我有一个值(99999)出现在_Audit表的Value列中,但不是第二个表的Value列,尽管代码只是将所有数据从同一个源转储到这两个表中!我不确定它是否重要,但是这个存储过程从SSIS包的执行SQL任务开始,其IsolationLevel为“Serializable”。也就是说,我没有明确地在代码中的任何地方使用事务,并且该Execute SQL Task的TransactionOption被设置为“Supported”。我不知道这是否与这个问题有关。

insert into FraudScoreIdentifyingData_Audit
select 'Post-IdentifyingData Update', GETDATE(), FraudCriteriaId, AccountId, IdentifyingDataId, IdentifyingDataTypeId, Value, Score
from @tempFraudScore;

insert into FraudScoreIdentifyingData
select GETDATE(), FraudCriteriaId, AccountId, IdentifyingDataId, IdentifyingDataTypeId, Value, Score, 1
from @tempFraudScore;

以下是两个表的模式:

enter image description here

2 个答案:

答案 0 :(得分:0)

不能说出造成问题的原因。

Parent Table=FraudScore

Child Table=IdentifyingData

它们是如何相关的?首先你在FraudScore中插入记录,然后使用输出子句,如果你有多个插入,在IdentifyingData中插入记录

但即使问题因此而无法解决,这也是使用OUTPUT clause的理想情况。

    --data type similar to IdentifyingData
declare @tbl table(Id int,Value int,IdentifyingDataTypeId int)
declare @CurrentDateTime datetime=GETDATE()

begin try
begin transaction

insert into IdentifyingData (EntryDateTime, IdentifyingDataTypeId
, Value, Source)
OUTPUT INSERTED.Id, INSERTED.Value, INSERTED.IdentifyingDataTypeId  
        INTO @tbl  
select distinct @CurrentDateTime, tfs.IdentifyingDataTypeId
, tfs.Value, 'SSIS'
from @tempFraudScore tfs
where not exists (
    select id.IdentifyingDataTypeId, id.Value
    from IdentifyingData id
    where tfs.IdentifyingDataTypeId = id.IdentifyingDataTypeId
        and tfs.Value = id.Value
);


update tfs
set tfs.IdentifyingDataId = id.Id
from @tempFraudScore tfs
    inner join @tbl id on
        tfs.Value = id.Value and
        tfs.IdentifyingDataTypeId = id.IdentifyingDataTypeId;

insert into FraudScore (EntryDateTime, FraudCriteriaId, AccountId, 
IdentifyingDataId, Score, Source)
select distinct
    @CurrentDateTime EntryDateTime,
    tfs.FraudCriteriaId,
    tfs.AccountId,
    tfs.IdentifyingDataId,
    tfs.Score,
    'SSIS'
from @tempFraudScore tfs
    inner join FraudCriteria fc on
        tfs.FraudCriteriaId = fc.Id
            and fc.UniqueEntryPeriod = 0
where not exists (
    select fs.AccountId, fs.FraudCriteriaId, fs.IdentifyingDataId
    from FraudScore fs
    where tfs.AccountId = fs.AccountId
        and tfs.FraudCriteriaId = fs.FraudCriteriaId
        and tfs.IdentifyingDataId = fs.IdentifyingDataId
);
COMMIT
end TRY
begin CATCH
if(@@trancount>0)
ROLLBACK
end CATCH

答案 1 :(得分:0)

事实证明,我的一个大型存储过程中隐藏了一个删除语句,这些语句写错了导致问题。

在寻找这个问题的原因时,我还有一位DBA和我坐在一起,他确定了我的SSIS流程的一部分,即重组索引;但它正在这样做,因为程序包继续运行并填充所有必要的基础表(包括具有孤立记录的表)。据他说,重组或重建表上的索引,同时尝试向这些表添加或删除记录也可能导致此问题;虽然在我的具体情况下,它是错误编写的单个删除语句。