Это невозможно без использования динамического SQL, если ваши данные смоделированы как есть, то есть пары ключ-значение в Table_LKP_AlertMastInfo
и столбцы в Table_RegistrationInfo
. Так что с этим из нашего пути, давайте сделаем это. Полный код хранимой процедуры, предоставляющий точные результаты, которые вам нужны, приведен в конце, я последую за объяснением того, что она делает.
Поскольку предупреждения указываются в виде пар ключ-значение (имя поля - значение поля), нам сначала нужно получить данные кандидата в том же формате. UNPIVOT
может исправить это, если мы сможем получить список полей. Если бы у нас было только два поля, которые вы упомянули в вопросе, это было бы довольно просто, что-то вроде:
SELECT CandidateId, DistrictID
, FieldName
, FieldValue
FROM Table_RegistrationInfo t
UNPIVOT (FieldValue FOR FieldName IN (AreYouMarried, Gender)) upvt
Конечно, это не так, поэтому нам нужно динамически выбрать список полей, которые нас интересуют, и предоставить это. Поскольку вы работаете в 2008 R2, STRING_AGG еще не доступен, поэтому мы будем использовать трюк XML, чтобы объединить все поля в одну строку и предоставить ее для вышеприведенного запроса. .
DECLARE @sql NVARCHAR(MAX)
SELECT @sql = CONCAT('SELECT CandidateId, DistrictID
, FieldName
, FieldValue
FROM Table_RegistrationInfo t
UNPIVOT (FieldValue FOR FieldName IN (',
STUFF((
SELECT DISTINCT ',' + ami.FieldName
FROM Table_LKP_AlertMastInfo ami
FOR XML PATH(''), TYPE).value('.', 'NVARCHAR(MAX)'), 1, 1, ''), ')) upvt')
PRINT @sql
Это дает почти точный результат в виде запроса, который я написал Далее нам нужно где-то хранить эти данные. Временные столы на помощь. Давайте создадим один и вставим в него, используя этот динамический SQL.
CREATE TABLE #candidateFields
(
CandidateID VARCHAR(50),
DistrictID INT,
FieldName NVARCHAR(200),
FieldValue NVARCHAR(1000)
);
INSERT INTO #candidateFields
EXEC sp_executesql @sql
-- (8 rows affected)
-- We could index this for good measure
CREATE UNIQUE CLUSTERED INDEX uxc#candidateFields on #candidateFields
(
CandidateId, DistrictId, FieldName, FieldValue
);
Отлично, теперь у нас есть оба набора данных - предупреждения и данные-кандидаты - в одном формате. Это вопрос объединения, чтобы найти совпадения между:
SELECT cf.CandidateID, COUNT(*) AS matches
FROM #candidateFields cf
INNER
JOIN Table_LKP_AlertMastInfo alerts
ON alerts.DistrictID = cf.DistrictID
AND alerts.FieldName = cf.FieldName
AND alerts.AlertOptionValue = cf.FieldValue
GROUP BY cf.CandidateID
Обеспечивает желаемый вывод для данных выборки:
CandidateID matches
-------------------------------------------------- -----------
Can001 2
Can002 1
Can003 1
(3 rows affected)
Так что теперь мы можем соединить все это вместе, чтобы сформировать хранимую процедуру многократного использования:
CREATE PROCEDURE dbo.findMatches
AS
BEGIN
SET NOCOUNT ON;
DECLARE @sql NVARCHAR(MAX)
SELECT @sql = CONCAT('SELECT CandidateId, DistrictID
, FieldName
, FieldValue
FROM Table_RegistrationInfo t
UNPIVOT (FieldValue FOR FieldName IN (',
STUFF((
SELECT DISTINCT ',' + ami.FieldName
FROM Table_LKP_AlertMastInfo ami
FOR XML PATH(''), TYPE).value('.', 'NVARCHAR(MAX)'), 1, 1, ''), ')) upvt')
CREATE TABLE #candidateFields
(
CandidateID VARCHAR(50),
DistrictID INT,
FieldName NVARCHAR(200),
FieldValue NVARCHAR(1000)
);
INSERT INTO #candidateFields
EXEC sp_executesql @sql
CREATE UNIQUE CLUSTERED INDEX uxc#candidateFields on #candidateFields
(
CandidateId, DistrictId, FieldName
);
SELECT cf.CandidateID, COUNT(*) AS matches
FROM #candidateFields cf
JOIN Table_LKP_AlertMastInfo alerts
ON alerts.DistrictID = cf.DistrictID
AND alerts.FieldName = cf.FieldName
AND alerts.AlertOptionValue = cf.FieldValue
GROUP BY cf.CandidateID
END;
Выполнить с
EXEC dbo.findMatches
Вам, конечно, нужно настроить типы и, возможно, добавить сюда кучу других вещей, например, обработку ошибок, но это должно привести вас к правильному пути. Вам понадобится индекс покрытия для этой таблицы оповещений, и он должен быть довольно быстрым даже при большом количестве записей.