2016-04-15 3 views
0

Мне была задана задача использовать курсор для дублирования таблиц. Скажем, теперь у меня есть 3 таблицы для дублирования: Компания, Person_Link & Лицо. Это отношения «от одного до многих», поскольку одна компания может иметь несколько человек.SQL Server - дубликаты нескольких таблиц с курсорами

Это мой код:

SET ANSI_NULLS ON 
GO 
SET QUOTED_IDENTIFIER ON 
GO 

ALTER PROCEDURE [dbo].[DuplicateCompanyInfo] 
    @Comp_CompanyId NVARCHAR(80) 
AS 
BEGIN 
    SET NOCOUNT ON; 

    DECLARE @CompanyID NVARCHAR(30), 
      @PersonID NVARCHAR(30), 
      @PersonLinkID NVARCHAR(30), 
      @AddressLinkID NVARCHAR(30), 
      @AddressID NVARCHAR(30), 
      @PhoneLinkID NVARCHAR(30), 
      @PhoneID NVARCHAR(30) 

    EXEC @companyId = crm_next_id 5 
    EXEC @PersonId = crm_next_id 13 
    EXEC @PersonLinkId = crm_next_id 31 
    EXEC @AddressLinkId = crm_next_id 21 
    EXEC @AddressId = crm_next_id 1 
    EXEC @PhoneLinkId = crm_next_id 10208 
    EXEC @PhoneId = crm_next_id 14 

    -- Add Company 
    INSERT INTO Company 
    (
     Comp_CompanyId, Comp_PrimaryPersonId, Comp_PrimaryAddressId, Comp_Name, Comp_Type, Comp_Status, Comp_CreatedBy, 
     Comp_CreatedDate, Comp_UpdatedBy, Comp_UpdatedDate, Comp_TimeStamp, Comp_SecTerr, Comp_WebSite 
    ) 
    SELECT @companyId, @PersonId, @AddressId, Comp_Name, Comp_Type, Comp_Status, Comp_CreatedBy, 
      Comp_CreatedDate, '1', GETDATE(), Comp_TimeStamp, Comp_SecTerr, Comp_WebSite 

    FROM Company 
    WHERE Comp_CompanyId = @comp_companyid 


------- PersonLink Cursor --------------------------------------------- 
    -- Declare Variables 
    DECLARE @c_PeLi_PersonLinkId NVARCHAR(30) 
    DECLARE @c_PeLi_PersonId NVARCHAR(30) 
    DECLARE @c_PeLi_CompanyID NVARCHAR(30) 
    DECLARE @c_PeLi_CreatedBy NVARCHAR(30) 
    DECLARE @c_PeLi_CreatedDate NVARCHAR(30) 
    DECLARE @c_PeLi_UpdatedBy NVARCHAR(30) 
    DECLARE @c_PeLi_UpdatedDate NVARCHAR(30) 
    DECLARE @c_PeLi_TimeStamp NVARCHAR(30) 


    --Declare Cursor 
    DECLARE @getPeLiID CURSOR 
    SET @getPeLiID= CURSOR FOR 
    SELECT PeLi_PersonLinkId, PeLi_PersonId, PeLi_CompanyID, PeLi_CreatedBy, PeLi_CreatedDate, PeLi_UpdatedBy, 
     PeLi_UpdatedDate, PeLi_TimeStamp 
    FROM Person_Link 
    INNER JOIN Person 
    ON PeLi_PersonId = Pers_PersonId 
    AND PeLi_CompanyID = @comp_companyid 

    --Open Cursor & fetch 1st row into variables 
    OPEN @getPeLiID 
    FETCH NEXT FROM @getPeLiID INTO @c_PeLi_PersonLinkId, @c_PeLi_PersonId, @c_PeLi_CompanyID, @c_PeLi_CreatedBy, 
            @c_PeLi_CreatedDate, @c_PeLi_UpdatedBy, @c_PeLi_UpdatedDate, @c_PeLi_TimeStamp 


    --Fetch successful 
    --Check for a new row 
    WHILE @@FETCH_STATUS = 0 
    BEGIN 

     --EXEC @PersonLinkId = crm_next_id 31 


    INSERT INTO Person_Link 
    (
     PeLi_PersonLinkId, PeLi_PersonId, PeLi_CompanyID, PeLi_CreatedBy, PeLi_CreatedDate, PeLi_UpdatedBy, 
     PeLi_UpdatedDate, PeLi_TimeStamp 
    ) 
    VALUES 
    (
     @PersonLinkId, @PersonId, @CompanyId, @c_PeLi_CreatedBy, @c_PeLi_CreatedDate, '1', GETDATE(), @c_PeLi_TimeStamp 
    ) 


    --Get next available row into variables 
    FETCH NEXT FROM @getPeLiID INTO @c_PeLi_PersonLinkId, @c_PeLi_PersonId, @c_PeLi_CompanyID, @c_PeLi_CreatedBy, 
            @c_PeLi_CreatedDate, @c_PeLi_UpdatedBy, @c_PeLi_UpdatedDate, @c_PeLi_TimeStamp 

    END 

    CLOSE @getPeLiID 
    DEALLOCATE @getPeLiID 


------- Person Cursor ------------------------------------------------- 
    -- Declare Variables 
    DECLARE @c_Pers_PersonId NVARCHAR(30) 
    DECLARE @c_Pers_CompanyId NVARCHAR(30) 
    DECLARE @c_Pers_PrimaryUserId NVARCHAR(30) 
    DECLARE @c_Pers_FirstName NVARCHAR(30) 
    DECLARE @c_Pers_SecTerr NVARCHAR(30) 
    DECLARE @c_Pers_CreatedBy NVARCHAR(30) 
    DECLARE @c_Pers_CreatedDate NVARCHAR(30) 
    DECLARE @c_Pers_UpdatedBy NVARCHAR(30) 
    DECLARE @c_Pers_UpdatedDate NVARCHAR(30) 
    DECLARE @c_Pers_TimeStamp NVARCHAR(30) 


    --Declare Cursor 
    DECLARE @getPersID CURSOR 
    SET @getPersID= CURSOR FOR 
    SELECT Pers_PersonId, Pers_CompanyId, Pers_PrimaryUserId, Pers_FirstName, Pers_SecTerr, Pers_CreatedBy, 
      Pers_CreatedDate, Pers_UpdatedBy, Pers_UpdatedDate, Pers_TimeStamp 
    FROM Person 
    INNER JOIN Person_Link 
    ON Pers_PersonId = PeLi_PersonId 
    AND PeLi_CompanyID = @comp_companyid  


    --Open Cursor & fetch 1st row into variables 
    OPEN @getPersID 
    FETCH NEXT FROM @getPersID INTO @c_Pers_PersonId, @c_Pers_CompanyId, @c_Pers_PrimaryUserId, @c_Pers_FirstName, 
            @c_Pers_SecTerr, @c_Pers_CreatedBy, @c_Pers_CreatedDate, @c_Pers_UpdatedBy, 
            @c_Pers_UpdatedDate, @c_Pers_TimeStamp 


    --Fetch successful 
    --Check for a new row 
    WHILE @@FETCH_STATUS = 0 
    BEGIN 

    --EXEC @PersonId = crm_next_id 13 


    INSERT INTO Person 
    (
     Pers_PersonId, Pers_CompanyId, Pers_PrimaryUserId, Pers_FirstName, Pers_SecTerr, Pers_CreatedBy, 
     Pers_CreatedDate, Pers_UpdatedBy, Pers_UpdatedDate, Pers_TimeStamp 
    ) 
    VALUES 
    (
     @PersonId, @companyId, @c_Pers_PrimaryUserId, @c_Pers_FirstName, @c_Pers_SecTerr, @c_Pers_CreatedBy, 
     @c_Pers_CreatedDate, '1', GETDATE(), @c_Pers_TimeStamp 
    ) 


    --Get next available row into variables 
    FETCH NEXT FROM @getPersID INTO @c_Pers_PersonId, @c_Pers_CompanyId, @c_Pers_PrimaryUserId, @c_Pers_FirstName, 
            @c_Pers_SecTerr, @c_Pers_CreatedBy, @c_Pers_CreatedDate, @c_Pers_UpdatedBy, 
            @c_Pers_UpdatedDate, @c_Pers_TimeStamp 

    END 

    CLOSE @getPersID 
    DEALLOCATE @getPersID 

Это моя структура таблицы:

компании Таблица:

comp_companyid | comp_primarypersonid | comp_primaryaddressid | comp_name 
------------------------------------------------------------------------- 
2    | 2     | 2      | company 2 
3    | 3     | 3      | company 3 

Person Таблица:

pers_personid | pers_companyid  | pers_primaryaddressid | pers_name 
------------------------------------------------------------------------- 
2    | 2     | 2      | person 2 
3    | 3     | 3      | person 3 
4    | 2     | 2      | person 4 

Person Ссылка Таблица:

peli_personlinkid | peli_personid  | peli_companyid 
------------------------------------------------------------------------- 
2     | 2     | 2     
3     | 3     | 3         

У меня нет никакой проблемы, исполняющий хранимую процедуру, когда есть только один человек принадлежал к 1 компании, но когда компания имеет 2 человек и выше, ряд 2-го лица не будет дублироваться, только первый из них.

Сообщение об ошибке будет выскочить:

Msg 2627, Level 14, State 1, процедура DuplicateCompanyInfo, Линия 80
Нарушение ограничения PRIMARY KEY 'PK__Person_L__BCD268642CF2ADDF. Невозможно вставить дубликат ключа в объект «dbo.Person_Link».

Msg 2627, Level 14, State 1, процедура DuplicateCompanyInfo, линия 141
Нарушение ограничения PRIMARY KEY 'PK__Person__381A5AC529221CFB. Невозможно вставить дубликат ключа в объект «dbo.Person».

я могу это исправить, удалив комментарий --EXEC @PersonLinkId = crm_next_id 31 & --EXEC @PersonID = crm_next_id 13 после того, как курсор начал так, что они будут генерировать новый идентификатор каждый раз, когда дублируется. Но это приведет к тому, что & Pers_PersonID & PeLi_PersonID не подсчитан, потому что каждый из них будет генерировать собственный новый идентификатор на основе их дублирования таблицы вместо применения внешних ключей друг друга.

Пожалуйста, помогите мне! Заранее благодарим за ваше время & усилием! Desmond

+2

Зачем использовать курсоры? Кажется, это слишком сложно? –

+0

Привет, сэр, см. Мой комментарий, который ответил на ответ Имрана ниже для объяснения. В таблицах может быть много повторяющихся записей, поэтому я хочу идти по строке за строкой с помощью курсора. –

ответ

1

Извините, у меня нет доступа к SQL-серверу прямо сейчас.

Я не вижу ваши определения таблиц, в которые вы вставляете данные. Но из-за ошибки похоже, что ваше определение таблицы неверно. т. е. выбор первичного ключа неверен для таблиц person и person_link. Ваш первичный ключ должен быть внешним ключом.

Во-вторых, почему курсоры? если вам просто нужно дублировать данные из одного набора таблиц другому, почему бы просто не использовать запрос? есть ли какая-либо конкретная причина использовать курсор?

UPDATE: Из обновленной структуры таблицы, первичные и внешние ключи не ясны, но похоже comp_companyid является первичным ключом в таблице компании, которая связана, как внешний ключ в лице (pers_companyid) и Person_Link (peli_companyid).

Теперь, если структура таблиц, как это:

компании Таблица: comp_companyid (PK)

Person Таблица: pers_personid (PK) и pers_companyid (FK)

Таблица связи человека: peli_personlinkid (PK) и peli_personid (FK), peli_companyid (FK)

Я не вижу проблемы с дублированием, если вы не вставляете дубликаты в столбцах PK.

Теперь, внимательно посмотрев на свой код, вы забираете peli_personlinkid в переменную @c_PeLi_PersonLinkId.

FETCH СЛЕДУЮЩИЙ ИЗ @getPeLiID INTO @c_PeLi_PersonLinkId, @c_PeLi_PersonId, @c_PeLi_CompanyID, @c_PeLi_CreatedBy, @c_PeLi_CreatedDate, @c_PeLi_UpdatedBy, @c_PeLi_UpdatedDate, @c_PeLi_TimeStamp

Но когда вы вставляете данные, которые вы не вставляя это значение, вместо этого вы вставляете @PersonLinkId в первичный ключ. Поскольку это значение исходит из другой хранимой процедуры (я не знаю, что делает эта хранимая процедура, но выглядит как генерирование следующего id и возврат). Что вы выполняете в начале процедуры

EXEC @PersonLinkId = crm_next_id 31

Таким образом, в цикле вы продолжаете вставляя это значение для каждого person_link. Это, конечно, нарушение ограничения PK, если в таблице будет больше одного person_link. И точно такая же проблема с таблицей Person.

Именно поэтому вы получаете ошибки при первичном ключевом нарушении.

Вместо того чтобы вставлять это значение каждый раз, вы должны вставить значение, полученное из @c_PeLi_PersonLinkId, который извлекает строку.

Надеюсь, что это поможет сейчас, и вы сможете решить проблему.

Честно говоря, я по-прежнему считаю, что вы можете поговорить со своим старшим и можете легко избежать курсоров в этой ситуации, и вы можете достичь всего этого с помощью простых инструкций вставки и выбора, и это будет намного лучше и быстрее. Но если вы не можете заменить курсоры, вы можете просто исправить хранимую процедуру как идентифицированную и предложенную выше.

+0

Просьба научить меня, как определить свой первичный ключ в «Личности» и «Личность», чтобы он мог быть иностранным ключом от Компании? Мой старший сказал, что должен использовать курсор в этом случае, так как это много-много отношений, поскольку у меня есть еще несколько других таблиц для дублирования: 1. Компания Телефон (Факс) 2. Компания PhoneLink (Факс) 3. Компания Телефон (Бизнес) 4. Компания PhoneLink (Бизнес) 5. лицо Телефон (факс) 6. лицо PhoneLink (факс) 7. лицо Телефон (Бизнес) 8. лицо PhoneLink (Бизнес) 9. Адрес 10. AddressLink + Person + PersonLink + Компания суммирует до 13 таблиц. Может быть много дубликатов записей с –

+0

@DesmondChau Если первичный ключ в вашей таблице компании является внешним ключом в таблицах Person & PersonLink, тогда не используйте его как PrimaryKey в этих двух таблицах, если вам не нужны отношения один к одному. Используйте любой другой, например. некоторые столбцы Identity в качестве первичного ключа для этих таблиц. – Imran

+0

@DesmondChau Как это отношения «многие ко многим»? любезно обменивайтесь табличной структурой. В последнем случае даже вы связываетесь со многими таблицами, но я не вижу здесь использования курсоров. – Imran

Смежные вопросы