Tsql 从一个表迁移到另一个表时避免重复

Tsql 从一个表迁移到另一个表时避免重复,tsql,Tsql,我需要从旧书表迁移数据: create table dbo.Books_OLD ( Id int identity not null constraint PK_Books_OLD_Id primary key (Id), Title nvarchar (200) not null, Image varbinary (max) null, Preview varbinary (max) null ) 要创建新的表结构,请执行以下操作: create table dbo.B

我需要从旧书表迁移数据:

create table dbo.Books_OLD ( 
  Id int identity not null constraint PK_Books_OLD_Id primary key (Id),
  Title nvarchar (200) not null,
  Image varbinary (max) null, 
  Preview varbinary (max) null
) 
要创建新的表结构,请执行以下操作:

create table dbo.Books ( 
  Id int identity not null constraint PK_Books_Id primary key (Id),
  Title nvarchar (200) not null 
)    

create table dbo.Files (
  Id int identity not null constraint PK_Files_Id primary key (Id),
  Content varbinary (max) null,
  Name nvarchar (280) null
)

create table dbo.BookFiles (
  BookId int not null, 
  FileId int not null, 
    constraint PK_BookFiles_Id primary key (BookId, FileId)
)

alter table dbo.BookFiles
add constraint FK_BookFiles_BookId foreign key (BookId) references Books(Id) on delete cascade on update cascade,
    constraint FK_BookFiles_FileId foreign key (FileId) references Files(Id) on delete cascade on update cascade;
迁移应按如下方式运行:

Books_OLD.Title => Create new Book with given Title value
Books_OLD.Image => Create new File with Image content.
                   Create new BookFile to associate File to Book.
Books_OLD.Preview => Create new File with Preview content.
                     Create new BookFile to associate File to Book.
我能够迁移数据,但在运行此操作时:

select FileId
from BookFiles
group by FileId
having count(*) > 1;
我有复本。我不应该有重复的文件ID。我错过了什么

我的迁移代码是:

DECLARE @BOOKS table (
  BookId int,
  Image varbinary(max),
  Preview varbinary(max)
)

MERGE Books AS d
USING Books_OLD AS s
ON 0 = 1
WHEN NOT MATCHED
THEN INSERT (Title)
VALUES (s.Title)
OUTPUT INSERTED.Id, s.Image, s.Preview
INTO @BOOKS;

INSERT Files (Content, Created)
SELECT t.Content, GETUTCDATE()
FROM @BOOKS i
CROSS APPLY (VALUES (Preview, 'Preview'), (Image, 'Image')) t(Content, ContentType)
WHERE Content IS NOT NULL

INSERT BookFiles (BookId, FileId)
SELECT i.BookId, f.Id
FROM @BOOKS i
JOIN Files f
ON f.Content = i.Image

UNION ALL

SELECT i.BookId, f.Id
FROM @BOOKS i
JOIN Files f
ON f.Content = i.Preview
有些图书可以有两个文件,即图像和预览,这样BookId可以在图书文件中出现多次

但旧表中的每个文件图像或预览应该只与一本书关联。所以奇怪的是,我在BookFiles中复制了FileId

我遗漏了什么?

如果您的旧书中有相同的图像或不同书籍的预览,请使用此部分的原始代码:

INSERT BookFiles (BookId, FileId)
SELECT i.BookId, f.Id
FROM @BOOKS i
JOIN Files f
ON f.Content = i.Image
在进行内部联接时,它将返回更多结果,因为可以联接来自不同书籍的两个图像或预览。重复的文件ID实际上是一个坏记录,因为BookId与特定的图像或预览不对应,即使它们是相同的

您可以使用另一个名为@Files的表变量,类似于Files表结构,只需再添加一列,即BookId,然后:

最后,从@Files中选择所有需要的列,将它们插入到文件中

更新:请参考以下完整代码:

   DECLARE @BOOKS table (
  BookId int,
  Image varbinary(max),
  Preview varbinary(max)
)
--Added @File Variable
DECLARE @Files table
( 
BookId int,
Content varbinary (max) null,
Created nvarchar (280) null,
Id int identity(1,1) not null primary key
)  

MERGE Books AS d
USING Books_OLD AS s
ON 0 = 1
WHEN NOT MATCHED
THEN INSERT (Title)
VALUES (s.Title)
OUTPUT INSERTED.Id, s.Image, s.Preview
INTO @BOOKS;

INSERT @Files (BookId,Content, Created) --
SELECT i.BookId,t.Content, GETUTCDATE()
FROM @BOOKS i
CROSS APPLY (VALUES (Preview, 'Preview'), (Image, 'Image')) t(Content, ContentType)
WHERE Content IS NOT NULL

INSERT BookFiles (BookId, FileId)
SELECT i.BookId, f.Id
FROM @BOOKS i
JOIN @Files f
ON f.Content = i.[Image]
AND f.BookId = i.BookId  --added joining condition

UNION ALL

SELECT i.BookId, f.Id
FROM @BOOKS i
JOIN @Files f
ON f.Content = i.Preview
AND f.BookId = i.BookId  --added joining condition

--Last insert all needed from @File into File
INSERT INTO Files (Content, Created)
SELECT content,Created
FROM @Files

PS:不确定dbo.File是否有拼写错误,您的表定义中有名称,但插入时,创建了它

您是否有不同书籍的相同图像或预览?@LONG在books\u旧表中,您可以看到每本书都有自己的图像,并在自己的列中预览。但我不确定是否一个图像或预览在多本书中是不同的。但如果是这样,我的代码在迁移时是如何做到的?也许我遗漏了什么……如果我的意图不是让一本书有一个或多个图像/内容,那么为什么要采用这种设计呢?即使你修复了这个插件,你的数据库在将来也无法解决这个问题。我采用这种设计是因为我在数据库中有许多表使用文件,所以我没有使用带有FK的BookFiles、带有FK的PostFiles等等,而是使用一个集中的Files表。事实上,有些文件可能是共享的。但是,如果我要迁移数据,我想为书中的每个图像/预览创建一个新文件,而不是让它们共享。我刚刚测试了它,事实上在Books\u旧表中,我有几行具有相同的图像或相同的预览。如何更改代码以解决此问题?抱歉,我试图将您的解决方案集成到我的代码中,但我可能缺少某些内容。。。上一个街区怎么样?其中显示:交叉应用值预览、“预览”、图像、“图像”t内容,ContentType@MiguelMoura现在检查一下,可能会有一些打字错误,但基本的想法是:您的代码有问题。选中此行:插入BookFiles BookId,FileId从我加入文件的书籍中选择i.BookId,f.Id。。。文件表中没有Id。我说得通吗?@MiguelMoura,啊,是的,错过了标识Id列,已更新。这是我尝试过的。但当我运行代码时,我得到以下错误:INSERT语句与外键约束FK_BookFiles_Files_FileId冲突。冲突发生在数据库BooksNewDb、表dbo.Files、列“Id”中。知道有什么问题吗?
   DECLARE @BOOKS table (
  BookId int,
  Image varbinary(max),
  Preview varbinary(max)
)
--Added @File Variable
DECLARE @Files table
( 
BookId int,
Content varbinary (max) null,
Created nvarchar (280) null,
Id int identity(1,1) not null primary key
)  

MERGE Books AS d
USING Books_OLD AS s
ON 0 = 1
WHEN NOT MATCHED
THEN INSERT (Title)
VALUES (s.Title)
OUTPUT INSERTED.Id, s.Image, s.Preview
INTO @BOOKS;

INSERT @Files (BookId,Content, Created) --
SELECT i.BookId,t.Content, GETUTCDATE()
FROM @BOOKS i
CROSS APPLY (VALUES (Preview, 'Preview'), (Image, 'Image')) t(Content, ContentType)
WHERE Content IS NOT NULL

INSERT BookFiles (BookId, FileId)
SELECT i.BookId, f.Id
FROM @BOOKS i
JOIN @Files f
ON f.Content = i.[Image]
AND f.BookId = i.BookId  --added joining condition

UNION ALL

SELECT i.BookId, f.Id
FROM @BOOKS i
JOIN @Files f
ON f.Content = i.Preview
AND f.BookId = i.BookId  --added joining condition

--Last insert all needed from @File into File
INSERT INTO Files (Content, Created)
SELECT content,Created
FROM @Files