Вставьте или обновите данные, когда строки совпадают или нет SQL Server - PullRequest
0 голосов
/ 31 октября 2018

У меня есть таблица ProjectTemplateSection:

    [ProjectID] [int] 
    [ProjectTemplateID]
    [SectionID] [int]
    [IsActive] [bit] 
    [SectionOrderNumber] [int] 

с примерами данных вот так:

  ProjectID  TemplateCloneId    SectionCloneId IsActive SectionOrderNumber
 -----------------------------------------------------------------------
    1                   1               1         1         4
    1                   1               2         0         2
    1                   1               3         1         3

У нас есть проект, шаблон и модуль раздела, которые взаимосвязаны

  • Один шаблон будет иметь несколько разделов
  • Один проект будет иметь один сопоставленный шаблон

Когда пользователь назначает шаблон для проекта, projectid, templateid и sectionid будут вставлены в ProjectTemplateSection.

Мне нужно предложение по разъяснению ниже

  • ЕСЛИ пользователь приходит и редактирует разделы для шаблона, такие как удаление раздела и добавление нового раздела. Если между разделами и шаблоном существует какое-либо сопоставление, тогда флаг IsActive должен быть ложным. Если нет сопоставления, тогда он должен вставить.

Должен ли я сделать запрос на выборку для существующего отображения для выбранного шаблона и получить записи, сравнить с новым отображением, вставить новые записи и обновить старое отображение, т. е. сделать флаг IsActive ложным

Пожалуйста, предложите, какое решение является лучшим для этого сценария

1 Ответ

0 голосов
/ 31 октября 2018

Попробуйте использовать MERGE:

CREATE TABLE TestProjectTemplateSection(
  ProjectID int,
  ProjectTemplateID int,
  SectionID int,
  IsActive bit,
  SectionOrderNumber int
)

INSERT TestProjectTemplateSection(ProjectID,ProjectTemplateID,SectionID,IsActive,SectionOrderNumber)VALUES
(1,1,1,1,4), 
(1,1,2,0,2),
(1,1,3,1,3)

И процедура для вставки / обновления / деактивации с помощью:

CREATE PROC SetTestProjectTemplateSection
  @ProjectID int,
  @ProjectTemplateID int,
  @SectionID int,
  @IsActive int=1,
  @SectionOrderNumber int=NULL
AS

  MERGE TestProjectTemplateSection trg
  USING
    (
      SELECT
        @ProjectID ProjectID,
        @ProjectTemplateID ProjectTemplateID,
        @SectionID SectionID,
        @IsActive IsActive,
        @SectionOrderNumber SectionOrderNumber
    ) src
  ON trg.ProjectID=src.ProjectID AND trg.ProjectTemplateID=src.ProjectTemplateID AND trg.SectionID=src.SectionID

  WHEN MATCHED THEN -- update IsActive and SectionOrderNumber
    UPDATE SET
      trg.IsActive=src.IsActive,
      trg.SectionOrderNumber=ISNULL(src.SectionOrderNumber,trg.SectionOrderNumber) -- if NULL then not change it

  WHEN NOT MATCHED BY TARGET THEN -- insert new row
    INSERT(ProjectID,ProjectTemplateID,SectionID,IsActive,SectionOrderNumber)
    VALUES(src.ProjectID,src.ProjectTemplateID,src.SectionID,src.IsActive,src.SectionOrderNumber);

GO

Демо-версия:

-- case 1 - update
EXEC SetTestProjectTemplateSection 1,1,2,1
EXEC SetTestProjectTemplateSection 1,1,2,1,111 -- set new order number

SELECT *
FROM TestProjectTemplateSection

-- case 2 - insert
EXEC SetTestProjectTemplateSection 2,1,2,1,123

SELECT *
FROM TestProjectTemplateSection

-- case 3 - deactive
EXEC SetTestProjectTemplateSection 2,1,2,0

SELECT *
FROM TestProjectTemplateSection

Я думаю, что в качестве варианта вы можете использовать STRING_SPLIT для списка разделов (см. @ListOfSectionID):

CREATE PROC SetTestProjectTemplateSections
  @ProjectID int,
  @ProjectTemplateID int,
  @ListOfSectionID varchar(100), -- e.g. '1,2,3,4'
  @IsActive int=1
AS

  MERGE TestProjectTemplateSection trg
  USING
    (
      SELECT
        @ProjectID ProjectID,
        @ProjectTemplateID ProjectTemplateID,
        CAST(value AS int) SectionID,
        @IsActive IsActive
      FROM STRING_SPLIT(@ListOfSectionID,',')
    ) src
  ON trg.ProjectID=src.ProjectID AND trg.ProjectTemplateID=src.ProjectTemplateID AND trg.SectionID=src.SectionID

  WHEN MATCHED THEN
    UPDATE SET
      trg.IsActive=src.IsActive

  WHEN NOT MATCHED BY TARGET THEN
    INSERT(ProjectID,ProjectTemplateID,SectionID,IsActive)
    VALUES(src.ProjectID,src.ProjectTemplateID,src.SectionID,src.IsActive);

GO

Но STRING_SPLIT работает для SQL Server 2017. Для другой версии SQL Server вы можете найти пользовательскую функцию для разбиения. Например - строка разделения T-SQL

Тест:

EXEC SetTestProjectTemplateSections 1,1,'1,2,3,4',0

SELECT *
FROM TestProjectTemplateSection

В качестве варианта можно использовать параметр таблицы:

CREATE TYPE TypeForProjectTemplateSection AS table(
  ProjectID int,
  ProjectTemplateID int,
  SectionID int,
  IsActive bit,
  SectionOrderNumber int
)
GO

И используйте этот тип в своей процедуре:

CREATE PROC SetTestProjectTemplateSectionFromTable
  @ProjectTemplateSectionDate dbo.TypeForProjectTemplateSection READONLY -- need to use READONLY here
AS

  MERGE TestProjectTemplateSection trg
  USING @ProjectTemplateSectionDate src
  ON trg.ProjectID=src.ProjectID AND trg.ProjectTemplateID=src.ProjectTemplateID AND trg.SectionID=src.SectionID

  WHEN MATCHED THEN -- update IsActive and SectionOrderNumber
    UPDATE SET
      trg.IsActive=src.IsActive,
      trg.SectionOrderNumber=src.SectionOrderNumber

  WHEN NOT MATCHED BY TARGET THEN -- insert new row
    INSERT(ProjectID,ProjectTemplateID,SectionID,IsActive,SectionOrderNumber)
    VALUES(src.ProjectID,src.ProjectTemplateID,src.SectionID,src.IsActive,src.SectionOrderNumber);

GO

Как его использовать:

ОБЪЯВИТЬ @Table dbo.TypeForProjectTemplateSection

INSERT @Table(ProjectID,ProjectTemplateID,SectionID,IsActive,SectionOrderNumber)VALUES
(1,1,1,1,111), 
(1,1,2,1,222)

EXEC SetTestProjectTemplateSectionFromTable @Table -- use it as parameter

SELECT *
FROM TestProjectTemplateSection

И вы можете использовать его из C #:

SqlCommand cmd = new SqlCommand("SetTestProjectTemplateSectionFromTable", con);
cmd.CommandType = CommandType.StoredProcedure;

DataTable tbl = new DataTable();
tbl.Columns.Add("ProjectID", typeof(int));
tbl.Columns.Add("ProjectTemplateID", typeof(int));
tbl.Columns.Add("SectionID", typeof(int));
tbl.Columns.Add("IsActive", typeof(bool)); // Check it because I don't remember how to use type bit here
tbl.Columns.Add("SectionOrderNumber", typeof(int));

tbl.Rows.Add(1,1,1,true,111);
tbl.Rows.Add(1,1,2,true,222);

cmd.Parameters.AddWithValue("@ProjectTemplateSectionDate", tbl);

cmd.ExecuteNonQuery();
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...