Условный выбор строки

#sql-server #tsql #sql-server-2014

#sql-сервер #tsql #sql-server-2014

Вопрос:

Я пытаюсь выбрать наиболее подходящую (наиболее общую) строку из таблицы

 CREATE TABLE #T(Id int, Bid int, Did int,Pid int, Vid int, SomeData varchar(10))

INSERT INTO #T
VALUES(1,1,1,1,1,'Data1'),
      (2,1,1,NULL,5,'Data2'),
      (3,1,1,NULL,6,'Data3'),
      (4,1,1,8,NULL,'Data4'),
      (5,1,NULL,NULL,NULL,'Data5')

SELECT *
FROM #T
  

Когда я использовал значения параметров, как показано ниже, строка, которую я ожидаю, имеет идентификатор 1, поскольку в ней содержатся все значения, переданные из параметров.

 DECLARE @Bid INT=1,
        @Did INT=1,
        @Pid INT=1,
        @Vid INT=1
  

Когда я использую приведенные ниже значения, строка, которую я ожидаю, имеет идентификатор 5. Потому что нет строки, соответствующей Pid 1 и Vid Null. Таким образом, наиболее общей строкой для этих параметров является строка с Id = 5.

 DECLARE @Bid INT=1,@Did INT =1,@Pid INT =1,@Vid INT =NULL
  

или

 DECLARE @Bid INT=1, @Did INT=1,@Pid INT=1,@Vid INT=6
  

Значение столбца NULL означает, что оно может быть применимо к любому значению параметра.

например, если all имеет значение null, это означает, что это своего рода основная строка. Но если основные «SomeData» должны быть другими, скажем, для Vid 1, тогда мы создаем строку, в которой все значения будут равны null, кроме Vid со значением 1.

Приоритет столбца слева направо.

Также, если значения являются

 DECLARE @Bid INT=1,@Did INT =1,@Pid INT =10,@Vid INT =1
  

Ожидаемая строка — это строка с идентификатором 5.

Я пробовал приведенный ниже запрос, но он возвращает несколько строк. Есть ли способ достичь чего-то подобного

 SELECT *
FROM #T
WHERE ((Bid = @Bid) OR Bid IS NULL) 
    AND ((Did = @Did) OR Did IS NULL)   
    AND ((Pid = @Pid) OR Pid IS NULL)   
    AND ((Vid = @Vid) OR Vid IS NULL)   
  

Ответ №1:

Если вам не нужно беспокоиться о дубликатах, т. Е. более чем одной строке с одинаковым количеством совпадений, то вы можете попробовать следующий запрос:

 SELECT TOP 1 t.Id
FROM
(
    SELECT Id,
           CASE WHEN Bid = @Bid OR (Bid IS NULL AND @Bid IS NOT NULL)
                THEN 1 ELSE 0 END AS BidMatch
           CASE WHEN Did = @Did OR (Did IS NULL AND @Did IS NOT NULL)
                THEN 1 ELSE 0 END AS DidMatch
           CASE WHEN Pid = @Pid OR (Pid IS NULL AND @Pid IS NOT NULL)
                THEN 1 ELSE 0 END AS PidMatch
           CASE WHEN Vid = @Vid OR (Vid IS NULL AND @Vid IS NOT NULL)
                THEN 1 ELSE 0 END AS VidMatch
    FROM #T
) t
ORDER BY t.BidMatch DESC,
         t.DidMatch DESC,
         t.PidMatch DESC,
         t.VidMatch DESC
  

Вы можете просто удалить TOP 1 предложение в начале запроса, чтобы увидеть все идентификаторы, отсортированные по убыванию того, насколько близко они соответствуют входным переменным.

Комментарии:

1. Это намного лучше. Единственная проблема — дубликат. Если у меня есть приоритет столбца слева направо, можем ли мы использовать это для устранения дубликатов?

2. Что вы подразумеваете под слева направо? Можете ли вы привести наглядный пример того, что вы имеете в виду? Имейте в виду, что упорядочивание таким образом может привести к путанице, потому что существует очень много перестановок даже всего с 4 столбцами.

3. Например. здесь мы вычисляем количество совпадений. Если у нас есть две строки 1, 8, 1, NULL и 1, NULL, 1,5, и мы передаем значения параметров 1,8,NULL,5, то обе строки будут иметь количество совпадений 2. Но я ожидаю получить 1-ю строку в качестве результата. Потому что он соответствует 1,8 по порядку, прежде чем сопоставлять 5 как vid во второй строке. Полезно ли это?

4. Это бесполезно, потому что вы не указали систему ранжирования. Например, 1, NULL, NULL, NULL и NULL, 8, NULL, 5 с помощью ввода 1, 8, NULL, 5 … первая запись совпадает с первой, но только с первой. Но считаются ли два последующих меньших совпадения больше или меньше , чем первое совпадение? Надеюсь, вы понимаете, к чему это приводит…

5. Если я передам 1,1,10,1 , он получит строку с идентификатором 1, как большинство совпадений. Но это будет неверно, поскольку эта строка специфична для PID-1, а здесь мы ищем PID-10. Таким образом, в этом случае наилучшим соответствием является последняя строка (с идентификатором 5)