Таблица циклов SQL вставляет записи в новую таблицу, затем берет новый идентификатор и вставляет в другую таблицу - PullRequest
0 голосов
/ 26 марта 2019

Я нахожусь в процессе миграции старой унаследованной системы, которая имеет в основном плоские таблицы базы данных со слишком большим количеством столбцов. Каждый новый параметр требует нового столбца и т. Д., Поэтому таблицы становятся невероятно большими. Я пытаюсь изменить эту структуру на реляционную и пытаюсь перенести старые существующие данные в новую структуру. Вот пример старой таблицы:

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.

Если бы вы могли помочь мне с сценарием, который мог бы достичь этого, я был бы очень признателен!

Ответы [ 4 ]

2 голосов
/ 26 марта 2019

Лучший способ справиться с этим - не использовать 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 голос
/ 26 марта 2019

Вы можете получить вновь вставленный идентификатор, используя предложение вывода

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 ()
Он может дать вам другой идентификатор, чем вы ожидаете, это может произойти, когда есть, например, триггер, который вставляет в другую таблицу.
Кроме того, используя предложение output, вы можете захватить больше полей, чем просто Id

Смотрите также это
@@ IDENTITY, SCOPE_IDENTITY (), OUTPUT и другие методы получения последнего идентификатора

0 голосов
/ 26 марта 2019
    DECLARE @FullName nvarchar(50), 
    @Email nvarchar(50),
    @Setting1 bit,
    @Setting1Value int,
    @Setting2 bit,
    @Setting2Value int,
    @Setting3 bit,
    @Setting3Value int 

    DECLARE @recentId INT

    DECLARE C CURSOR FOR 
        SELECT [FullName] , [Email] ,[Setting1], [Setting1Value], [Setting2], [Setting2Value], [Setting3], [Setting3Value]
        FROM @User_OLD

        OPEN C
    FETCH NEXT FROM C INTO @FullName, @Email ,@Setting1 ,@Setting1Value ,@Setting2 ,@Setting2Value ,@Setting3 ,@Setting3Value  

    WHILE @@FETCH_STATUS = 0 
    BEGIN

        INSERT INTO @User_NEW(FullName, Email)
        VALUES(@FullName, @Email);

        SELECT @recentId = SCOPE_IDENTITY()

        INSERT INTO @UserSetting(UserId, SettingName, SettingValue, CreatedOn)
        VALUES(@recentId, @Setting1 , @Setting1Value , GETDATE())

        INSERT INTO @UserSetting(UserId, SettingName, SettingValue, CreatedOn)
        VALUES(@recentId, @Setting2 , @Setting2Value , GETDATE())

        INSERT INTO @UserSetting(UserId, SettingName, SettingValue, CreatedOn)
        VALUES(@recentId, @Setting3 , @Setting3Value , GETDATE())

        FETCH NEXT FROM C INTO @FullName, @Email ,@Setting1 ,@Setting1Value ,@Setting2 ,@Setting2Value ,@Setting3 ,@Setting3Value 

    END

    CLOSE C
    DEALLOCATE C    
0 голосов
/ 26 марта 2019

Если вы ищете процесс, который позволит вам получить ключ из недавно вставленной строки, чтобы вы могли использовать его в последующем коде, то это то, что вы ищете - SCOPE_IDENTITY ().

https://docs.microsoft.com/en-us/sql/t-sql/functions/scope-identity-transact-sql?view=sql-server-2017

Declare PassedKey Integer; 

INSERT INTO User_New values (...) 
SET PassedKey = SCOPE_IDENTITY()

INSERT INTO User_Setting values (PassedKey, ...)
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...