Загрузка данных
USE myNewVasya;
UPDATE r
SET r.otzyv = s.scoreOtzyv
FROM dbo.sb_reports AS r
JOIN dbo.dat_mts_scores AS s
ON s.kodReport = r.kod
AND s.kodMember = r.kodMember
JOIN dbo.dat_members AS m
ON m.kod = s.kodMember
AND m.kodMerop = s.kodMerop
JOIN dbo.dat_activity AS a
ON a.kod = s.kodMerop
WHERE a.dtMerop >= CONVERT(datetime, '20260922', 112)
AND r.a1 LIKE N'otzyvMTS[_]%'
AND NULLIF(LTRIM(RTRIM(s.scoreOtzyv)), N'') IS NOT NULL
AND (
r.otzyv IS NULL
OR r.otzyv <> s.scoreOtzyv
OR DATALENGTH(r.otzyv) <> DATALENGTH(s.scoreOtzyv)
);
SELECT @@ROWCOUNT AS updatedReports;
USE [myNewVasya];
GO
SET ANSI_NULLS ON;
GO
SET QUOTED_IDENTIFIER ON;
GO
ALTER PROCEDURE [dbo].[VI5_0_1pr8_1]
@BatchSize int = 200
AS
BEGIN
SET NOCOUNT ON;
SET XACT_ABORT ON;
IF @BatchSize < 1 OR @BatchSize > 5000
THROW 51010, 'BatchSize must be between 1 and 5000', 1;
-- Сопоставляем ответы с участниками.
-- UNION удаляет повторное совпадение по двум ключам.
SELECT a.kod AS answerKod, m.kod AS kodMember
INTO #Pairs
FROM dbo.sb_answer AS a
JOIN dbo.dat_members AS m
ON m.kod = a.kodMember
UNION
SELECT a.kod, m.kod
FROM dbo.sb_answer AS a
JOIN dbo.dat_members AS m
ON m.participantId = a.memberId;
CREATE UNIQUE CLUSTERED INDEX IX_Pairs
ON #Pairs(kodMember, answerKod);
-- Сохраняем прежний порядок:
-- сначала последний ответ, затем отбор открытых волн.
;WITH ranked AS
(
SELECT
p.kodMember,
a.kod AS answerKod,
a.kodMerop,
a.labelF,
a.answer,
ROW_NUMBER() OVER
(
PARTITION BY p.kodMember, a.labelF
ORDER BY a.kod DESC
) AS rn
FROM #Pairs AS p
JOIN dbo.sb_answer AS a
ON a.kod = p.answerKod
)
SELECT
r.kodMember,
r.answerKod,
r.labelF,
r.answer
INTO #Latest
FROM ranked AS r
JOIN dbo.dat_activity AS a
ON a.kod = r.kodMerop
JOIN dbo.spr_wave AS w
ON w.kod = a.kodWave
WHERE r.rn = 1
AND (w.kodProject = 8 OR w.kodProject >= 11)
AND w.[close] = 0;
CREATE CLUSTERED INDEX IX_Latest
ON #Latest(kodMember, answerKod);
SELECT DISTINCT
l.kodMember,
l.answerKod,
s.nmSubject
INTO #Mapped
FROM #Latest AS l
JOIN dbo.spr_pollsToMind AS p
ON p.textPoll = l.labelF
JOIN dbo.spr_pollsSubject AS s
ON s.kod = p.kodSubject;
CREATE CLUSTERED INDEX IX_Mapped
ON #Mapped(kodMember, answerKod);
SELECT DISTINCT kodMember
INTO #Members
FROM #Mapped;
CREATE UNIQUE CLUSTERED INDEX IX_Members
ON #Members(kodMember);
CREATE TABLE #Batch
(
kodMember int NOT NULL PRIMARY KEY
);
DECLARE
@lastMember int = NULL,
@ID int,
@nmSubject nvarchar(50),
@nmField nvarchar(50),
@targetTable nvarchar(128),
@valueExpression nvarchar(100),
@sql nvarchar(max),
@batchNo int = 0,
@memberCount int,
@changed int,
@rows int,
@copiedReviews int;
WHILE 1 = 1
BEGIN
TRUNCATE TABLE #Batch;
INSERT INTO #Batch(kodMember)
SELECT TOP (@BatchSize) kodMember
FROM #Members
WHERE @lastMember IS NULL
OR kodMember > @lastMember
ORDER BY kodMember;
SET @memberCount = @@ROWCOUNT;
IF @memberCount = 0
BREAK;
SELECT @lastMember = MAX(kodMember)
FROM #Batch;
SET @batchNo = @batchNo + 1;
SET @ID = 0;
SET @changed = 0;
WHILE 1 = 1
BEGIN
SELECT TOP (1)
@ID = kod,
@nmField = nmField,
@nmSubject = nmSubject,
@targetTable = targetTable
FROM dbo.spr_pollsSubject
WHERE kod > @ID
ORDER BY kod;
IF @@ROWCOUNT = 0
BREAK;
IF NOT EXISTS
(
SELECT 1
FROM #Mapped AS m
JOIN #Batch AS b
ON b.kodMember = m.kodMember
WHERE m.nmSubject = @nmSubject
)
CONTINUE;
-- Отзывы сохраняем целиком и в Unicode.
-- Для остальных полей оставляем прежнее поведение.
SET @valueExpression =
CASE
WHEN
(@targetTable = N'dat_mts_scores'
AND @nmField = N'scoreOtzyv')
OR
(@targetTable = N'sb_reports'
AND @nmField = N'otzyv')
THEN N'CONVERT(nvarchar(max), l.answer)'
ELSE N'CAST(l.answer AS varchar(240))'
END;
SET @sql = N'
UPDATE t
SET ' + QUOTENAME(@nmField) + N' = '
+ @valueExpression + N'
FROM dbo.' + QUOTENAME(@targetTable) + N' AS t
JOIN #Batch AS b
ON b.kodMember = t.kodMember
JOIN #Mapped AS m
ON m.kodMember = b.kodMember
AND m.nmSubject = @subject
JOIN #Latest AS l
ON l.kodMember = m.kodMember
AND l.answerKod = m.answerKod;
SET @affected = @@ROWCOUNT;';
SET @rows = 0;
EXEC sys.sp_executesql
@sql,
N'@subject nvarchar(50), @affected int OUTPUT',
@subject = @nmSubject,
@affected = @rows OUTPUT;
SET @changed = @changed + @rows;
END;
RAISERROR
(
N'PR8 batch=%d members=%d updated_field_rows=%d',
10, 1,
@batchNo, @memberCount, @changed
) WITH NOWAIT;
END;
-- Копирование отзывов выполняется даже при пустом sb_answer.
-- Это позволяет перенести ранее обработанные отзывы.
-- Источник: dat_mts_scores.scoreOtzyv.
-- Связь строго по отчёту, участнику и мероприятию.
UPDATE r
SET r.otzyv = s.scoreOtzyv
FROM dbo.sb_reports AS r
JOIN dbo.dat_mts_scores AS s
ON s.kodReport = r.kod
AND s.kodMember = r.kodMember
JOIN dbo.dat_members AS m
ON m.kod = s.kodMember
AND m.kodMerop = s.kodMerop
JOIN dbo.dat_activity AS a
ON a.kod = s.kodMerop
WHERE a.dtMerop >= CONVERT(datetime, '20260922', 112)
AND r.a1 LIKE N'otzyvMTS[_]%'
AND NULLIF(LTRIM(RTRIM(s.scoreOtzyv)), N'') IS NOT NULL
AND
(
r.otzyv IS NULL
OR r.otzyv <> s.scoreOtzyv
OR DATALENGTH(r.otzyv) <> DATALENGTH(s.scoreOtzyv)
);
SET @copiedReviews = @@ROWCOUNT;
RAISERROR
(
N'PR8 copied_reviews=%d',
10, 1,
@copiedReviews
) WITH NOWAIT;
END;
GO
USE [myNewVasya];
GO
DECLARE @kodMember int = 10773311;
DECLARE @kodMerop int = 16461;
DECLARE @participantId nvarchar(250);
SELECT @participantId = m.participantId
FROM dbo.dat_members AS m
WHERE m.kod = @kodMember
AND m.kodMerop = @kodMerop;
-- 1. Участник, отчёты и состояние сертификата.
SELECT
m.kod AS kodMember,
m.kodMerop,
m.participantId,
m.profileId,
m.beInOn,
m.timeInMerop,
a.dtMerop,
w.kodProject,
w.[close] AS waveClosed,
r.kod AS kodReport,
r.a1,
r.tipReport,
r.formatCon2,
r.listenerCntInteger,
r.manFIO,
r.nmOrg,
r.vidOrg,
r.otzyv,
c.kodReport AS certificateReport,
c.mtsCertNumber,
c.formReceived,
c.lastCheckAt,
c.lastError
FROM dbo.dat_members AS m
JOIN dbo.dat_activity AS a
ON a.kod = m.kodMerop
JOIN dbo.spr_wave AS w
ON w.kod = a.kodWave
LEFT JOIN dbo.sb_reports AS r
ON r.kodMember = m.kod
LEFT JOIN dbo.dat_mts_certificates AS c
ON c.kodMember = m.kod
AND c.kodMerop = m.kodMerop
WHERE m.kod = @kodMember
AND m.kodMerop = @kodMerop
ORDER BY r.kod DESC;
-- Собираем ответы только этого мероприятия.
-- Два источника не суммируем как уникальные ответы:
-- одна запись может присутствовать в обоих.
SELECT
CAST(N'sb_answer' AS nvarchar(30)) AS sourceTable,
a.kod AS answerKod,
a.kodMerop,
a.kodMember,
a.memberId,
a.pollId,
a.labelF AS savedQuestion,
a.answer,
a.srvsDT
INTO #PostformCheck
FROM dbo.sb_answer AS a
WHERE a.kodMerop = @kodMerop
AND
(
a.kodMember = @kodMember
OR
(
NULLIF(@participantId, N'') IS NOT NULL
AND a.memberId = @participantId
)
)
UNION ALL
SELECT
N'sb_answerData',
a.kod,
a.kodMerop,
a.kodMember,
a.memberId,
a.pollId,
a.labelF,
a.answer,
a.srvsDT
FROM dbo.sb_answerData AS a
WHERE a.kodMerop = @kodMerop
AND
(
a.kodMember = @kodMember
OR
(
NULLIF(@participantId, N'') IS NOT NULL
AND a.memberId = @participantId
)
);
-- 2. Есть ли post_form в каждом источнике.
SELECT
src.sourceTable,
COUNT(p.answerKod) AS allAnswerRows,
SUM(CASE WHEN p.pollId = N'post_form'
THEN 1 ELSE 0 END) AS postFormAnswerRows,
MAX(CASE WHEN p.pollId = N'post_form'
THEN p.srvsDT END) AS lastPostFormSavedAt
FROM
(
VALUES
(N'sb_answer'),
(N'sb_answerData')
) AS src(sourceTable)
LEFT JOIN #PostformCheck AS p
ON p.sourceTable = src.sourceTable
GROUP BY src.sourceTable
ORDER BY src.sourceTable;
-- 3. Какие типы ответов фактически сохранены.
SELECT
sourceTable,
pollId,
COUNT(*) AS answerRows,
MIN(srvsDT) AS firstSavedAt,
MAX(srvsDT) AS lastSavedAt
FROM #PostformCheck
GROUP BY sourceTable, pollId
ORDER BY sourceTable, pollId;
-- 4. Ответы и действующие привязки вопросов.
-- Показываем все типы, чтобы увидеть также сертификат
-- и записи, у которых pollId уже изменён очисткой.
SELECT
p.sourceTable,
p.answerKod,
p.srvsDT,
p.kodMerop,
p.kodMember,
p.memberId,
p.pollId,
p.savedQuestion,
p.answer,
s.nmSubject,
s.targetTable,
s.nmField,
CASE
WHEN pm.kodSubject IS NULL
THEN N'Нет привязки вопроса'
WHEN s.kod IS NULL
THEN N'Не найдено описание поля'
ELSE N'Привязка найдена'
END AS mappingState
FROM #PostformCheck AS p
LEFT JOIN dbo.spr_pollsToMind AS pm
ON pm.textPoll = p.savedQuestion
LEFT JOIN dbo.spr_pollsSubject AS s
ON s.kod = pm.kodSubject
ORDER BY p.sourceTable, p.answerKod;
DROP TABLE #PostformCheck;
GO