我正在迁移一个旧的遗留系统,该遗留系统的数据库表大部分都是平面的,列太多。每个新设置都需要一个新列,以此类推,表格变得越来越大。我试图将这种结构更改为关系结构,并努力将旧的现有数据迁移到新结构中。这是我们拥有的旧表的示例:
CREATE TABLE [dbo].[User_OLD](
[Id] [int] IDENTITY(1,1) NOT NULL,
[FullName] [nvarchar](50) NULL,
[Email] [nvarchar](50) NULL,
[Setting1] [bit] NULL,
[Setting1Value] [int] NULL,
[Setting2] [bit] NULL,
[Setting2Value] [int] NULL,
[Setting3] [bit] NULL,
[Setting3Value] [int] NULL,
CONSTRAINT [PK_User] PRIMARY KEY CLUSTERED ([Id] ASC));
此表正在迁移到多个表中,下面是一个示例:
CREATE TABLE [dbo].[User_NEW](
[Id] [int] IDENTITY(1,1) NOT NULL,
[FullName] [nvarchar](50) NULL,
[Email] [nvarchar](50) NULL,
CONSTRAINT [PK_User] PRIMARY KEY CLUSTERED ([Id] ASC));
CREATE TABLE [dbo].[UserSetting](
[Id] [int] IDENTITY(1,1) NOT NULL,
[UserId] [int] NOT NULL,
[SettingName] [varchar](250) NOT NULL,
[SettingValue] [varchar](250) NOT NULL,
[CreatedOn] [datetime] NOT NULL,
CONSTRAINT [PK_UserSetting] PRIMARY KEY CLUSTERED ([Id] ASC),
CONSTRAINT FK_UserSetting_User FOREIGN KEY ([UserId]) REFERENCES User_NEW(Id));
所以问题是我需要从User_OLD中获取一条记录并将其值插入User_NEW中,然后我需要将User_NEW.Id插入到UserSetting表中,并将相应的Setting1,Setting1Value插入新表中列SettingName和SettingValue。
如果您可以通过一个脚本帮助我实现这一目标,我将不胜感激!
答案 0 :(得分:2)
处理此问题的最佳方法是不使用SCOPE_IDENTITY或其他强制您使用RBAR的方法。对您的新表进行一些细微调整会使此过程变得更简单。
CREATE TABLE [dbo].[User_NEW](
[Id] [int] IDENTITY(1,1) NOT NULL,
[FullName] [nvarchar](50) NULL,
[Email] [nvarchar](50) NULL,
UserID_OLD int not null
CONSTRAINT [PK_User] PRIMARY KEY CLUSTERED ([Id] ASC));
是否注意到新列UserID_OLD?您可以在一条语句中插入所有用户,然后通过加入此表来开始规范化过程。
insert User_NEW
(
FullName
, Email
, UserID_OLD
)
select FullName
, Email
, Id
from User_OLD
insert UserSetting
(
UserId
, SettingName
, SettingValue
)
select Setting1
, Setting1Value
, un.Id
from User_OLD u
join User_NEW un on un.UserID_OLD = u.Id
然后,对所有属性/值组合重复此插入操作。迁移完成后,删除UserID_OLD列。
但是,您需要意识到所拥有的是实体属性值设计,并且这种类型的东西有很多陷阱。首先,您现在将所有内容都存储在varchar中,因此无法在数据库级别验证数据。您在这里还有一个性能炸弹,因为所有内容都必须不断转换为正确的数据类型。而且您必须小心转换,否则会出现转换错误。 EAV模式看起来确实很棒,但是在实践中它经常是有问题的。
答案 1 :(得分:1)
您可以使用输出子句获取新插入的ID
declare @OutputTbl table (ID INT)
declare @NewUserID int
insert into User_NEW (FullName, Email)
output inserted.Id into @OutputTbl(ID)
VALUES ('john doe', 'john@somewhere.com')
select @NewUserID = ID from @OutputTbl
现在您可以将@NewUserID用作所有插入客户表的键
提防使用SCOPE_IDENTITY()
它可能会给您另一个您期望的ID,例如当触发器插入另一个表时,就会发生这种情况。
另外,通过使用output子句,您可以捕获更多字段,而不仅仅是ID
另请参阅
@@IDENTITY, SCOPE_IDENTITY(), OUTPUT and other methods of retrieving last identity
答案 2 :(得分:0)
如果您正在寻找一个过程,该过程将允许您从新插入的行中获取密钥,以便可以在后续代码中使用它,那么这就是您要寻找的-SCOPE_IDENTITY()。
Declare PassedKey Integer;
INSERT INTO User_New values (...)
SET PassedKey = SCOPE_IDENTITY()
INSERT INTO User_Setting values (PassedKey, ...)
答案 3 :(得分:0)
<!DOCTYPE html>
<html>
<head>
<link href="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/4.2.1/css/bootstrap.min.css" rel="stylesheet">
</head>
<body>
<main class='container'>
<section class="row">
<form id='ui' class='col'>
<fieldset class="board border border-success rounded"></fieldset>
<section class='row'>
<article class='col'>
<fieldset class="btn-toolbar justify-content-between">
<label class='btn-group'>
<button class="btn btn-success add" type='button'>ADD</button>
<button class="btn btn-success color" type='button'>COLOR</button>
<button class="btn btn-success move" type='button'>MOVE</button>
<button class="btn btn-success clear" type='reset'>CLEAR</button>
</label>
</fieldset>
</article>
</section>
</form>
</section>
</main>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
</body>
</html>