У меня есть таблица 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 ложным
Подскажите, пожалуйста, лучшее решение для этого сценария.





Попробуйте использовать 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();
Спасибо, Леран, за быстрый ответ. Я отправлю список разделов, в одном шаблоне будет несколько разделов. Должен ли я отправлять разделы как значения, разделенные запятыми, и использовать цикл while и внутри цикла while использовать предложенный вами запрос слияния ИЛИ Следует ли мне обрабатывать на стороне C#, например, перебирать разделы и вызывать запрос слияния внутри цикла через ADO. сеть
Какую версию SQLServer вы используете?
Я использую как 2014, так и 2016, Забыл упомянуть, у меня есть еще один атрибут для раздела под названием Номер заказа, он также используется для упорядочивания раздела. При редактировании шаблона проекта меняются и номера заказа раздела.
Забыл упомянуть, что я обновил вопрос, у меня есть еще один атрибут для раздела под названием Номер заказа, он также используется для упорядочивания раздела. При редактировании шаблона проекта может измениться и порядковый номер раздела.
Я снова изменил свой ответ. Я думаю, что будет лучше использовать простой цикл на стороне C#, чем использовать сложную процедуру.
Я вспомнил, что в качестве параметра можно использовать таблицу. Я также добавил пример к своему ответу. Попробуйте протестировать и, возможно, этот вариант вам подойдет.
Конечно буду тестировать, спасибо за ответ
Я не буду закрывать как дубликат (пока), но вы должны проверить ответ, опубликованный Аароном Бертраном на эта почта