SQL - возвращает каждую запись только один раз - PullRequest
1 голос
/ 01 января 2011

Вот мои таблицы:

tblBusiness
BusinessID, BusinessName

tblTags
TagID, Tag

tblBusinessTagLink
BusinessID, TagID

К любому бизнесу могут быть применены несколько тегов.Теперь предположим, что пользователь выполняет фильтрацию, поэтому он находит только компании, помеченные как «Канцелярские товары» и «Технологии»

Какой оператор SQL мне следует использовать?Есть ли лучший дизайн для моих таблиц, чем то, что я здесь представил?

Ответы [ 3 ]

2 голосов
/ 01 января 2011
SELECT
  b.BusinessId,
  b.BusinessName 
FROM
  tblBusiness AS b
  INNER JOIN tblBusinessTagLink AS l ON l.BusinessId = b.BusinessId
  INNER JOIN tblTags            AS t ON t.TagId      = l.TagId
WHERE
  t.TagName IN ('Technology', 'Office Supplies')
GROUP BY
  b.BusinessId,
  b.BusinessName 

Это выбирает все предприятия, которые входят в одну из категорий.Чтобы выбрать только те, которые в обеих категориях, вы можете добавить

HAVING COUNT(*) = 2

Метод, который вы используете (три таблицы для представления отношения am: n), является стандартным способом решения этой задачи, вы можете оставить его.

Лично я бы не использовал «венгерскую нотацию» для имен таблиц (т.е. без «tbl») и не использовал бы имена таблиц во множественном числе (т.е. не «теги»), особенно когда другие таблицы не являются множественными.Либо.


Отвечая на первый комментарий ниже:

Для больших наборов данных производительность этого запроса зависит от индексов.Все первичные ключи нуждаются в индексе, естественно.В tblBusinessTagLink у вас должен быть составной индекс, охватывающий оба поля, и один дополнительный индекс для поля, которое не стоит на первом месте в составном индексе.

Идея WHERE keywords LIKE '%technology%' плохая, главным образом потому, что для любогоКак условия, отличные от поиска по полю, индекс не может быть использован (т. Е. Производительность будет быстро снижаться по мере роста набора данных), так как отчасти это должно быть WHERE ','+keywords+',' LIKE '%,technology,%' для начала, иначе вы получите частичные совпадения / ложные срабатывания.

Кроме того, запрос может быть более эффективным по TagId.Таким образом, вы можете полностью удалить одну таблицу из JOIN:

FROM 
  tblBusiness AS b 
  INNER JOIN tblBusinessTagLink AS l ON l.BusinessId = b.BusinessId 
WHERE 
  l.TagId IN (1, 2)

Если вы намереваетесь выполнить запрос по TagName, индекс в этом поле также будет абсолютно необходим.

0 голосов
/ 01 января 2011

Вы можете использовать операцию набора INTERSECT , чтобы объединить 2 запроса (один для «Канцелярские товары» и один для «Технологии»).

Однако, если вы используете MySQL (который не поддерживает INTERSECT), вы можете использовать UNION ALL с 'HAVING COUNT (*) = 2' , например, .


EDIT:

Вы также можете использовать второй вариант без UNION ALL, например, так:

select Name from tblBusiness
left join tblBusinessTagLink on tblBusinessTagLink.BusinessID = tblBusiness.ID
left join tblTags on tblTags.TagID = tblBusinessTagLink.TagID
where Tag = 'Office Supplies' or Tag = 'Technology'
group by name
having count(Name) = 2;
0 голосов
/ 01 января 2011

Вы можете использовать простой JOIN, чтобы получить запись

SELECT t.Tag, b.BusinessName 
FROM tblBusiness b, tblTags t, tblBusinessTagLink l
WHERE t.TagID = l.TagID 
AND l.BusinessID = b.BusinessID 
AND t.Tag = 'Office Supplies'
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...