维护自动内部关系表

时间:2012-04-12 19:28:14

标签: sql sql-server

我有几个表从某些日志自动获取数据。例如,假设我的表包含两列:

Country | someData
--------|---------
USA     | 123
Canada  | 4545
Mexico  | 4363
USA     | 3434
...

现在我在Country列中有很多重复,所以使用外键与国家的另一个表是有意义的但不幸的是,数据上传到表中的方式,我无法实现。插入数据的程序插入Country字符串,我无法更改(例如INSERT INTO表VALUES('USA',3232))

我想知道表是否有办法自动维护某种关系,使得它不会多次存储相同的字符串。

由于

3 个答案:

答案 0 :(得分:0)

让INSERT TRIGGER完成工作。

情景A)

插入数据的表有3列

CountryID INT NULL,
Country VARCHAR(50) NULL,
SomeData VARCHAR(MAX) NOT NULL

上传者执行INSERT INTO MyTable(Country, SameData) VALUES(...)

您的INSERT TRIGGER必须

  • 表示inserted表格
  • 中的每一行
  • 在另一个(引用的)表中找到匹配的CountryID(外键)
  • UPDATE SET CountryID with 匹配的外键
  • UPDATE SET Country = NULL清理空间

情景B)

两张桌子

上传者表

Country VARCHAR(50) NOT NULL,
SomeData VARCHAR(MAX) NOT NULL

目标表

CountryID INT NOT NULL,
SomeData VARCHAR(MAX)

您的INSERT TRIGGER必须

  • 表示inserted表格
  • 中的每一行
  • 使用匹配的外键
  • 将其重写为目标表

还可以使用INSTEAD OF INSERT TRIGGER(与经典的AFTER INSERT TRIGGER相比)尝试以上场景,因此Country列甚至没有写入DB - 它在运行中“转换”为CountryID。在场景B中,上传者的表可能实际上是一个视图(上传器插入视图而不是插入触发器来完成工作)。请参阅以下示例:http://msdn.microsoft.com/en-us/library/ms175089.aspx

答案 1 :(得分:0)

我不能保证这是遵循我刚刚了解到的最佳实践,但我不时需要这些需求并且我一直想要了解这一点,所以这就是我认为的答案使用而不是触发器的问题。

create table Country (
     id int primary key not null identity(1,1)
    ,name varchar(10)
)
go

create table Item (
     id int primary key not null identity(1,1)
    ,country_id int references Country(id)
    ,data varchar(100)
)
go

create view ItemView as
select C.name, I.data
from Item I inner join Country C on I.country_id = C.id
go

create trigger tr_Item_IOI on ItemView
instead of insert as begin

    set nocount on

      -- add the country if it does not exist
    if(not exists (select C.id from Country C inner join inserted I on C.name = I.name))
         insert into Country select distinct name from inserted

      -- insert an item using the country id for the inserted country name
    insert into Item (country_id, data)
    select C.id, I.data
    from Country C inner join inserted I on C.name = I.name

end
go

insert into ItemView values 
     ('USA', '123')
    ,('Canada', '4545')
    ,('Mexico', '4363')
    ,('USA', '3434')
go

select * from ItemView
select * from Country
select * from Item

enter image description here

答案 2 :(得分:-1)

我不明白这个问题。您可以拥有一个Country表,并且可以将文本表示用作Key,它不必是ID号(int,bigint等)。该表将包含每个国家的一个实例:美国,加拿大,墨西哥。

在您的关系中,您有另一个存储someData的表,其中可以包含多个条目,例如USA。好处是您的国家/地区表可以有更多关于对象的列(在本例中为国家/地区)。