Добро пожаловать в форум, Guest  >>   Войти | Регистрация | Поиск | Правила | В избранное | Подписаться
Все форумы / Microsoft SQL Server Новый топик    Ответить
 Помогите! CONTAINSTABLE по нескольким полям с объединением по "И" и по "ИЛИ"  [new]
DeviLooper
Member

Откуда:
Сообщений: 41
Суть такая. Есть таблица data в ней помимо прочего 4 текстовых поля с полнотекстовым индексом.
Нужно реализовать поиск по всем 4-м полям (для каждого поля своя строка поиска), объединяя эти условия по "И" или по "ИЛИ"
На выходе нужно получить 1 таблицу с полями [key] и [rank]
Плюс еще нужно отсеивать записи по другим полям таблицы data (например, по root_id)

Для "И" (т.е. когда должны совпасть все 4 строки) додумался до такого:

select s1.[key],s1.rank+s2.rank+s3.rank+s4.rank as rank from data,

containstable(data,[name],'"text1*"') as s1
inner join
containstable(data,[text],'"text2*"') as s2 on s2.[key] = s1.[key]
inner join
containstable(data,[actors],'"text3*"') as s3 on s3.[key] = s2.[key]
inner join
containstable(data,[author],'"text4*"') as s4 on s4.[key] = s3.[key]

where data.root_id = 1 and data.id = s1.[key];

Вроде бы все работает, как задумывал. Что-то оптимизировать/доработать тут можно?


А вот по "ИЛИ" (когда совпадает хотя бы 1 строка) не могу сообразить как лучше сделать.
Думал с помощью UNION:
select s.[key],s.[rank] from data, 
(
	select * from containstable(data,[name],'"text1*"') as s1
	union
	select * from containstable(data,[text],'"text2*"') as s2
	union
	select * from containstable(data,[actors],'"text3*"') as s3
	union
	select * from containstable(data,[author],'"text4*"') as s4
) as s

where data.root_id = 1 and data.id = s.[key];

Тоже вроде как работает, но в результирующей таблице могут быть дублирующиеся строки с одинаковым [key] (если сработало несколько containstable для одной и той же строки из data)
Т.е. по идее нужно еще в результирующей таблице объединить все дубликаты по [key] с вычислением их суммарного [rank].
Как бы это сделать?
22 авг 15, 15:00    [18054580]     Ответить | Цитировать Сообщить модератору
 Re: Помогите! CONTAINSTABLE по нескольким полям с объединением по "И" и по "ИЛИ"  [new]
churupaha
Member

Откуда: Краснодар
Сообщений: 1015
DeviLooper,

во внутреннем подзапросе

select [key], sum(rank) as rank
from
(
      /* портянка union'ов */
)
group by [key]
22 авг 15, 15:29    [18054618]     Ответить | Цитировать Сообщить модератору
 Re: Помогите! CONTAINSTABLE по нескольким полям с объединением по "И" и по "ИЛИ"  [new]
churupaha
Member

Откуда: Краснодар
Сообщений: 1015
+ union, заменить на union all, потому, как containstable возвращает и колонку rank, а он различный будет для строк с одним и тем же [key] в общем случае. из плана уйдет "distinct фаза" для объединения.
22 авг 15, 15:33    [18054625]     Ответить | Цитировать Сообщить модератору
 Re: Помогите! CONTAINSTABLE по нескольким полям с объединением по "И" и по "ИЛИ"  [new]
DeviLooper
Member

Откуда:
Сообщений: 41
churupaha,

Во, спасибо! То, что надо!
А так, в целом, нормальный запрос или что-то улучшить можно?
22 авг 15, 15:41    [18054636]     Ответить | Цитировать Сообщить модератору
 Re: Помогите! CONTAINSTABLE по нескольким полям с объединением по "И" и по "ИЛИ"  [new]
churupaha
Member

Откуда: Краснодар
Сообщений: 1015
DeviLooper
churupaha,

Во, спасибо! То, что надо!
А так, в целом, нормальный запрос или что-то улучшить можно?


запрос, как запрос. может и можно улучшить, но сегодня шаббат.
22 авг 15, 15:42    [18054638]     Ответить | Цитировать Сообщить модератору
 Re: Помогите! CONTAINSTABLE по нескольким полям с объединением по "И" и по "ИЛИ"  [new]
DeviLooper
Member

Откуда:
Сообщений: 41
churupaha,

Понятно, все равно спасибо. ;)
22 авг 15, 15:44    [18054640]     Ответить | Цитировать Сообщить модератору
 Re: Помогите! CONTAINSTABLE по нескольким полям с объединением по "И" и по "ИЛИ"  [new]
DeviLooper
Member

Откуда:
Сообщений: 41
Может, кому пригодится, вот итоговый запрос по "ИЛИ"

data.id - primary key

select [key],sum([rank]) as [rank]
from data,
(
	select * from containstable(data,[name],'"test1*"')
	union all
	select * from containstable(data,[text],'"test2*"')
	union all
	select * from containstable(data,[actors],'"test3*"')
	union all
	select * from containstable(data,[author],'"test4*"')
) as s
where id=s.[key] and root_id=1
group by s.[key];


если отсеивание по дополнительным полям не нужно, то, соответственно, убираем where и "data," из from
22 авг 15, 18:12    [18054908]     Ответить | Цитировать Сообщить модератору
Все форумы / Microsoft SQL Server Ответить