在SQL Server 2008中屏蔽或隐藏错误输入的数据

在SQL Server 2008中屏蔽或隐藏错误输入的数据,sql,sql-server,sql-server-2008,Sql,Sql Server,Sql Server 2008,好的,所以我的主题不是很有描述性,但下面是一个场景: 最终用户有向政府机构提交交易数据的法律义务。交易记录包含各种个人和组织的名称和地址。然而,最终用户经常拼错报告的个人和组织的名称,或者严重损坏地址等 最终用户提交的信息是合法的“文件”,因此接收信息的机构不能对其进行修改。此外,公众还可以查看和搜索交易。当政府机构注意到明显的拼写错误或地址不正确时,他们会用已知的正确值“隐藏”或“掩盖”该错误值。例如,如果最终用户输入“Arnie Schwarzeger”,代理商可以将该名称替换为“Arnol

好的,所以我的主题不是很有描述性,但下面是一个场景:

最终用户有向政府机构提交交易数据的法律义务。交易记录包含各种个人和组织的名称和地址。然而,最终用户经常拼错报告的个人和组织的名称,或者严重损坏地址等

最终用户提交的信息是合法的“文件”,因此接收信息的机构不能对其进行修改。此外,公众还可以查看和搜索交易。当政府机构注意到明显的拼写错误或地址不正确时,他们会用已知的正确值“隐藏”或“掩盖”该错误值。例如,如果最终用户输入“Arnie Schwarzeger”,代理商可以将该名称替换为“Arnold Schwarzenegger”。查看数据的公众可以看到(并搜索)正确的拼写,但可以在发现有问题的数据记录后查看最终用户输入的原始数据

希望这能很好地解释这个商业案例…请转到SQL部分!为了解决这个问题,我们有如下表:

CREATE TABLE [dbo].[SomeUserEnteredData](
    [Id] [uniqueidentifier] NOT NULL,
    [LastOrOrganizationName] [nvarchar](350) NOT NULL,  // data as entered by end-user
    [FirstName] [nvarchar](50) NULL, // data as entered by end-user
    [FullName]  AS ([dbo].[FullNameValue]([FirstName],[LastName])) PERSISTED,  // data as entered by end-user
    [MappedName]  AS ([dbo].[MappedNameValue]([FirstName],[LastName])))  // this is the 'override' data from the agency

CREATE TABLE [dbo].[CorrectionsByAgency](
    [Id] [uniqueidentifier] NOT NULL,
    [ReplaceName] [nvarchar](400) NOT NULL,
    [KeepName] [nvarchar](400) NOT NULL)

CREATE FUNCTION [dbo].[FullNameValue]
(
    @FirstName as NVARCHAR(40),
    @LastOrOrganizationName as NVARCHAR(350)
)
RETURNS NVARCHAR(400)
WITH SCHEMABINDING
AS
BEGIN
    DECLARE @result NVARCHAR(400)
    IF @FirstName = '' OR @FirstName is NULL
        SET @result = @LastOrOrganizationName
    ELSE 
        SET @result = @LastOrOrganizationName + ', ' + @FirstName
    RETURN @result
END

CREATE FUNCTION [dbo].[MappedNameValue]
(
    @FirstName as NVARCHAR(50),
    @LastOrOrganizationName as NVARCHAR(350)
)
RETURNS NVARCHAR(400)
AS
BEGIN
    DECLARE @result NVARCHAR(400)
    DECLARE @FullName NVARCHAR(400)
    SET @FullName = dbo.FullNameValue(@FirstName, @LastOrOrganizationName)
    SELECT top 1 @result = KeepName from CorrectionsByAgency where ReplaceName = @FullName
    if @result is null
        SET @result = @FullName
    RETURN @result
END
create table dbo.UserEnteredData (
  DocumentId uniqueidentifier not null primary key,
  UserEnteredName nvarchar(1000) not null,
  CorrectedNameId uniqueidentifier null,
  constraint FK_CorrectedNames foreign key (CorrectedNameId)
    references dbo.CorrectedNames (CorrectedNameId)
)

create table dbo.CorrectedNames (
  CorrectedNameId uniqueidentifier not null primary key,
  CorrectedName nvarchar(1000) not null
)
希望,如果我的样本不是太复杂,你可以看到,如果机构输入一个名称更正,它将替换所有拼写错误的名称。从业务逻辑的角度来看,这是完全正确的:机构工作人员只需输入一些更正,更正可以覆盖所有拼写错误的名称

从服务器性能的角度来看,这个解决方案很糟糕。无法索引计算的
SomeUserEnteredData.MappedName
列,也无法索引从该列读取的视图!如果我们不能为MappedName值编制索引,这就不可能满足我们的需要

我所能看到的唯一可能的替代方法是在最终用户创建的数据和机构创建的数据之间创建一个额外的链接表——当机构输入更正记录时,链接表中会为每一次出现的错误列值创建一条记录。不利的一面似乎是,对于机构用户输入的每一次更正,都有可能创建/销毁许多(数十万)链接记录


你们当中有谁对如何解决这个问题有很好的想法吗?

我不确定这是否直接回答了你的问题,但我会尽量简化整个过程:停止使用函数,保留“计算”值,并使用应用程序逻辑(可能在存储过程中)来管理数据

假设一个机构更正可以应用于许多用户输入的名称,那么您可以有如下内容:

CREATE TABLE [dbo].[SomeUserEnteredData](
    [Id] [uniqueidentifier] NOT NULL,
    [LastOrOrganizationName] [nvarchar](350) NOT NULL,  // data as entered by end-user
    [FirstName] [nvarchar](50) NULL, // data as entered by end-user
    [FullName]  AS ([dbo].[FullNameValue]([FirstName],[LastName])) PERSISTED,  // data as entered by end-user
    [MappedName]  AS ([dbo].[MappedNameValue]([FirstName],[LastName])))  // this is the 'override' data from the agency

CREATE TABLE [dbo].[CorrectionsByAgency](
    [Id] [uniqueidentifier] NOT NULL,
    [ReplaceName] [nvarchar](400) NOT NULL,
    [KeepName] [nvarchar](400) NOT NULL)

CREATE FUNCTION [dbo].[FullNameValue]
(
    @FirstName as NVARCHAR(40),
    @LastOrOrganizationName as NVARCHAR(350)
)
RETURNS NVARCHAR(400)
WITH SCHEMABINDING
AS
BEGIN
    DECLARE @result NVARCHAR(400)
    IF @FirstName = '' OR @FirstName is NULL
        SET @result = @LastOrOrganizationName
    ELSE 
        SET @result = @LastOrOrganizationName + ', ' + @FirstName
    RETURN @result
END

CREATE FUNCTION [dbo].[MappedNameValue]
(
    @FirstName as NVARCHAR(50),
    @LastOrOrganizationName as NVARCHAR(350)
)
RETURNS NVARCHAR(400)
AS
BEGIN
    DECLARE @result NVARCHAR(400)
    DECLARE @FullName NVARCHAR(400)
    SET @FullName = dbo.FullNameValue(@FirstName, @LastOrOrganizationName)
    SELECT top 1 @result = KeepName from CorrectionsByAgency where ReplaceName = @FullName
    if @result is null
        SET @result = @FullName
    RETURN @result
END
create table dbo.UserEnteredData (
  DocumentId uniqueidentifier not null primary key,
  UserEnteredName nvarchar(1000) not null,
  CorrectedNameId uniqueidentifier null,
  constraint FK_CorrectedNames foreign key (CorrectedNameId)
    references dbo.CorrectedNames (CorrectedNameId)
)

create table dbo.CorrectedNames (
  CorrectedNameId uniqueidentifier not null primary key,
  CorrectedName nvarchar(1000) not null
)
现在,您需要确保应用程序逻辑可以执行以下操作:

CREATE TABLE [dbo].[SomeUserEnteredData](
    [Id] [uniqueidentifier] NOT NULL,
    [LastOrOrganizationName] [nvarchar](350) NOT NULL,  // data as entered by end-user
    [FirstName] [nvarchar](50) NULL, // data as entered by end-user
    [FullName]  AS ([dbo].[FullNameValue]([FirstName],[LastName])) PERSISTED,  // data as entered by end-user
    [MappedName]  AS ([dbo].[MappedNameValue]([FirstName],[LastName])))  // this is the 'override' data from the agency

CREATE TABLE [dbo].[CorrectionsByAgency](
    [Id] [uniqueidentifier] NOT NULL,
    [ReplaceName] [nvarchar](400) NOT NULL,
    [KeepName] [nvarchar](400) NOT NULL)

CREATE FUNCTION [dbo].[FullNameValue]
(
    @FirstName as NVARCHAR(40),
    @LastOrOrganizationName as NVARCHAR(350)
)
RETURNS NVARCHAR(400)
WITH SCHEMABINDING
AS
BEGIN
    DECLARE @result NVARCHAR(400)
    IF @FirstName = '' OR @FirstName is NULL
        SET @result = @LastOrOrganizationName
    ELSE 
        SET @result = @LastOrOrganizationName + ', ' + @FirstName
    RETURN @result
END

CREATE FUNCTION [dbo].[MappedNameValue]
(
    @FirstName as NVARCHAR(50),
    @LastOrOrganizationName as NVARCHAR(350)
)
RETURNS NVARCHAR(400)
AS
BEGIN
    DECLARE @result NVARCHAR(400)
    DECLARE @FullName NVARCHAR(400)
    SET @FullName = dbo.FullNameValue(@FirstName, @LastOrOrganizationName)
    SELECT top 1 @result = KeepName from CorrectionsByAgency where ReplaceName = @FullName
    if @result is null
        SET @result = @FullName
    RETURN @result
END
create table dbo.UserEnteredData (
  DocumentId uniqueidentifier not null primary key,
  UserEnteredName nvarchar(1000) not null,
  CorrectedNameId uniqueidentifier null,
  constraint FK_CorrectedNames foreign key (CorrectedNameId)
    references dbo.CorrectedNames (CorrectedNameId)
)

create table dbo.CorrectedNames (
  CorrectedNameId uniqueidentifier not null primary key,
  CorrectedName nvarchar(1000) not null
)
  • 外部用户输入脏数据
  • 代理用户检查脏数据,并识别错误名称和更正名称
  • 应用程序检查更正的名称是否已存在
  • 如果否,请在dbo.CorrectedNames中创建新行
  • 在dbo.UserEnteredData中创建一个新行,并使用更正的NameId
  • 我假设事实上情况更为复杂,根据地址和其他数据以及姓名进行更正,但您描述的基本关系似乎足够简单。正如您所说,这些函数增加了很多开销,而且(对我来说)不清楚它们比直接存储您需要的数据有什么好处


    最后,我不理解你关于创建/销毁链接记录的评论;正确处理数据更改取决于您的应用程序逻辑。

    我不确定这是否直接回答了您的问题,但我会尝试简化整个过程:停止使用函数,保留“计算”值,并使用应用程序逻辑(可能在存储过程中)来管理数据

    假设一个机构更正可以应用于许多用户输入的名称,那么您可以有如下内容:

    CREATE TABLE [dbo].[SomeUserEnteredData](
        [Id] [uniqueidentifier] NOT NULL,
        [LastOrOrganizationName] [nvarchar](350) NOT NULL,  // data as entered by end-user
        [FirstName] [nvarchar](50) NULL, // data as entered by end-user
        [FullName]  AS ([dbo].[FullNameValue]([FirstName],[LastName])) PERSISTED,  // data as entered by end-user
        [MappedName]  AS ([dbo].[MappedNameValue]([FirstName],[LastName])))  // this is the 'override' data from the agency
    
    CREATE TABLE [dbo].[CorrectionsByAgency](
        [Id] [uniqueidentifier] NOT NULL,
        [ReplaceName] [nvarchar](400) NOT NULL,
        [KeepName] [nvarchar](400) NOT NULL)
    
    CREATE FUNCTION [dbo].[FullNameValue]
    (
        @FirstName as NVARCHAR(40),
        @LastOrOrganizationName as NVARCHAR(350)
    )
    RETURNS NVARCHAR(400)
    WITH SCHEMABINDING
    AS
    BEGIN
        DECLARE @result NVARCHAR(400)
        IF @FirstName = '' OR @FirstName is NULL
            SET @result = @LastOrOrganizationName
        ELSE 
            SET @result = @LastOrOrganizationName + ', ' + @FirstName
        RETURN @result
    END
    
    CREATE FUNCTION [dbo].[MappedNameValue]
    (
        @FirstName as NVARCHAR(50),
        @LastOrOrganizationName as NVARCHAR(350)
    )
    RETURNS NVARCHAR(400)
    AS
    BEGIN
        DECLARE @result NVARCHAR(400)
        DECLARE @FullName NVARCHAR(400)
        SET @FullName = dbo.FullNameValue(@FirstName, @LastOrOrganizationName)
        SELECT top 1 @result = KeepName from CorrectionsByAgency where ReplaceName = @FullName
        if @result is null
            SET @result = @FullName
        RETURN @result
    END
    
    create table dbo.UserEnteredData (
      DocumentId uniqueidentifier not null primary key,
      UserEnteredName nvarchar(1000) not null,
      CorrectedNameId uniqueidentifier null,
      constraint FK_CorrectedNames foreign key (CorrectedNameId)
        references dbo.CorrectedNames (CorrectedNameId)
    )
    
    create table dbo.CorrectedNames (
      CorrectedNameId uniqueidentifier not null primary key,
      CorrectedName nvarchar(1000) not null
    )
    
    现在,您需要确保应用程序逻辑可以执行以下操作:

    CREATE TABLE [dbo].[SomeUserEnteredData](
        [Id] [uniqueidentifier] NOT NULL,
        [LastOrOrganizationName] [nvarchar](350) NOT NULL,  // data as entered by end-user
        [FirstName] [nvarchar](50) NULL, // data as entered by end-user
        [FullName]  AS ([dbo].[FullNameValue]([FirstName],[LastName])) PERSISTED,  // data as entered by end-user
        [MappedName]  AS ([dbo].[MappedNameValue]([FirstName],[LastName])))  // this is the 'override' data from the agency
    
    CREATE TABLE [dbo].[CorrectionsByAgency](
        [Id] [uniqueidentifier] NOT NULL,
        [ReplaceName] [nvarchar](400) NOT NULL,
        [KeepName] [nvarchar](400) NOT NULL)
    
    CREATE FUNCTION [dbo].[FullNameValue]
    (
        @FirstName as NVARCHAR(40),
        @LastOrOrganizationName as NVARCHAR(350)
    )
    RETURNS NVARCHAR(400)
    WITH SCHEMABINDING
    AS
    BEGIN
        DECLARE @result NVARCHAR(400)
        IF @FirstName = '' OR @FirstName is NULL
            SET @result = @LastOrOrganizationName
        ELSE 
            SET @result = @LastOrOrganizationName + ', ' + @FirstName
        RETURN @result
    END
    
    CREATE FUNCTION [dbo].[MappedNameValue]
    (
        @FirstName as NVARCHAR(50),
        @LastOrOrganizationName as NVARCHAR(350)
    )
    RETURNS NVARCHAR(400)
    AS
    BEGIN
        DECLARE @result NVARCHAR(400)
        DECLARE @FullName NVARCHAR(400)
        SET @FullName = dbo.FullNameValue(@FirstName, @LastOrOrganizationName)
        SELECT top 1 @result = KeepName from CorrectionsByAgency where ReplaceName = @FullName
        if @result is null
            SET @result = @FullName
        RETURN @result
    END
    
    create table dbo.UserEnteredData (
      DocumentId uniqueidentifier not null primary key,
      UserEnteredName nvarchar(1000) not null,
      CorrectedNameId uniqueidentifier null,
      constraint FK_CorrectedNames foreign key (CorrectedNameId)
        references dbo.CorrectedNames (CorrectedNameId)
    )
    
    create table dbo.CorrectedNames (
      CorrectedNameId uniqueidentifier not null primary key,
      CorrectedName nvarchar(1000) not null
    )
    
  • 外部用户输入脏数据
  • 代理用户检查脏数据,并识别错误名称和更正名称
  • 应用程序检查更正的名称是否已存在
  • 如果否,请在dbo.CorrectedNames中创建新行
  • 在dbo.UserEnteredData中创建一个新行,并使用更正的NameId
  • 我假设事实上情况更为复杂,根据地址和其他数据以及姓名进行更正,但您描述的基本关系似乎足够简单。正如您所说,这些函数增加了很多开销,而且(对我来说)不清楚它们比直接存储您需要的数据有什么好处


    最后,我不理解你关于创建/销毁链接记录的评论;正确处理数据更改取决于您的应用程序逻辑。

    为了澄清创建/销毁注释……如果进行更正的机构用户改变了主意(或更可能是自己犯了错误),则需要重新评估之前应用的所有更正。我想我将遵循您建议的路径,但不直接更新“脏”数据表。我将在两个数据表之间放置一个链接表。(即UserEnteredData.Id=SomeLinkingTable.DataId和SomeLinkingTable.CorrectionId=CorrectedNames.Id)。如果进行更正的机构用户改变了主意(或更可能自己犯了错误),则澄清创建/销毁注释然后,所有以前应用的更正都需要重新评估。我想我将遵循您建议的路径,但不直接更新“脏”数据表。我将在两个数据表之间放置一个链接表。(即UserEnteredData.Id=SomeL