Сделать SQL, где оператор динамический для каждого значения из string_split - PullRequest
0 голосов
/ 30 апреля 2019

Я сейчас ищу таблицу с относительным статическим запросом. Это не идеальный запрос, потому что исходный поисковый запрос в этом примере - Denny drive. Входные данные поиска должны быть разделены пробелами (возможно, с string_split). В результате мне нужны только строки, где denny и drive в givenname, surename или streetaddress.

Это текущий запрос для zwei therms:

DECLARE @query1 NVARCHAR(MAX)
DECLARE @query2 NVARCHAR(MAX)

SET @query1='Denny'
SET @query2='drive'

SELECT
    *
FROM
    fakenames f
WHERE
    (givenname like '%' + @query1 + '%' OR surname like '%' + @query1 + '%' OR streetaddress like '%' + @query1 + '%') AND 
    (givenname like '%' + @query2 + '%' OR surname like '%' + @query2 + '%' OR streetaddress like '%' + @query2 + '%')

Можно ли сделать оператор where более гибким? Так что у меня может быть только одна переменная с SET @query='Denny drive vegas', и для каждого разделенного элемента оператор where объединяется с еще одной (givenname like '%' + @queryY + '%' OR surname like '%' + @queryY + '%' OR streetaddress like '%' + @queryY + '%')

Пример данных:

| givenname | surname  | streetaddress        |
|:----------|---------:|:--------------------:|
| Irene     | Williams | 2835 Crestview Manor |
| Denny     | Wade     | 885 Baker drive      |
| Denny     | Reese    | 129 Owagner Lane     |

Ожидаемый результат:

| givenname | surname  | streetaddress        |
|:----------|---------:|:--------------------:|
| Denny     | Wade     | 885 Baker drive      |

Ответы [ 3 ]

0 голосов
/ 30 апреля 2019

Это гибкий:

Table
Create Table fakenames
(
givenname nVarChar(25),
surname nVarChar(25),
streetaddress nVarChar(50)
)
Insert Into fakenames Values
('Denny','Smith','Main St'),
('Billy','vegas','Main St'),
('John','Travolta','Main St'),
('Mick','Jagger','Willow Ave'),
('Mary','Jane','Oak drive')

Запрос

Declare @query nVarChar(50) = 'Denny drive vegas'

;With cte As
(
SELECT
    f.*, 
    v1.value As val1,
    v2.value As val2,
    v3.value As val3
FROM
    fakenames f Left Join
    String_Split(@query,' ') v1 On f.givenname Like '%' + v1.value + '%' Left Join
    String_Split(@query,' ') v2 On f.surname Like '%' + v2.value + '%' Left Join
    String_Split(@query,' ') v3 On f.streetaddress Like '%' + v3.value + '%'
)
Select * From cte
WHERE
    val1 Is Not Null Or
    val2 Is Not Null Or
    val3 Is Not Null 

1007 * Результат *

givenname   surname streetaddress   val1    val2    val3
---------   ------- -------------   ---     ---     ---
Denny       Smith   Main St         Denny   NULL    NULL
Billy       vegas   Main St         NULL    vegas   NULL
Mary        Jane    Oak drive       NULL    NULL    drive
0 голосов
/ 30 апреля 2019

Если я правильно понимаю ваш вопрос, вы можете попробовать следующий подход.Вам нужно разделить текст поиска, используя STRING_SPLIT() (или другую функцию, если вы не используете SQL Server 2016+), и подсчитать совпадения для каждой части разделенного текста.

Ввод:

CREATE TABLE #fakenames (
   givenname varchar(100),
   surname varchar(100),
   streetaddress varchar(100)
)
INSERT INTO #fakenames
   (givenname, surname, streetaddress)
VALUES
   ('Irene', 'Williams', '2835 Crestview Manor'),
   ('Denny', 'Wade',     '885 Baker drive'),
   ('Denny', 'Reese',    '129 Owagner Lane')

Заявление:

DECLARE @query varchar(max)
SET @query = 'Denny drive'

SELECT f.*
FROM #fakenames f
CROSS APPLY STRING_SPLIT(@query, ' ') s
GROUP BY f.givenname, f.surname, f.streetaddress
HAVING 
   SUM(CASE 
       WHEN (givenname LIKE '%' + s.[value] + '%') OR 
            (surname LIKE '%' + s.[value] + '%') OR 
            (streetaddress LIKE '%' + s.[value] + '%') THEN 1 ELSE 0 END
   ) = (SELECT COUNT(*) FROM STRING_SPLIT(@query, ' '))

Вывод:

---------------------------------
givenname   surname streetaddress
---------------------------------
Denny       Wade    885 Baker drive
0 голосов
/ 30 апреля 2019

Это должно сделать, но это трудно переварить и, вероятно, медленно:

SELECT *
FROM t
WHERE NOT EXISTS (
    SELECT 1
    FROM STRING_SPLIT('denny drive', ' ') AS x
    WHERE NOT EXISTS (
        SELECT 1
        FROM (VALUES
            (t.givenname),
            (t.surname),
            (t.streetaddress)
        ) AS y(value)
        WHERE y.value LIKE '%' + x.value + '%'
    )
);

И это был мой оригинальный ответ, исправленный:

SELECT *
FROM t
WHERE EXISTS (
    SELECT 1
    FROM STRING_SPLIT('denny drive', ' ') AS x
    CROSS JOIN (VALUES (t.givenname, t.surname, t.streetaddress)) AS y(col1, col2, col3)
    HAVING COUNT(*) = COUNT(CASE WHEN y.col1 LIKE '%' + x.value + '%' OR
                                      y.col2 LIKE '%' + x.value + '%' OR
                                      y.col3 LIKE '%' + x.value + '%' THEN 1 END)
);

Db <> скрипка

...