Как сделать внутреннее соединение при сохранении уникальных строк

0

У меня есть тройственные отношения, в которых я устанавливаю связь между предложениями, профилями и навыками. Например, таблица тройственных отношений, называемая ternary, имеет идентификаторы трех таблиц в качестве первичного ключа. Это может выглядеть примерно так:

id_Offer    -   id_Profile  -   id_Skill
1           -   1           -   1
1           -   1           -   2
1           -   1           -   3
1           -   2           -   1
2           -   1           -   1
2           -   3           -   2
2           -   1           -   3
2           -   5           -   1
[and so on, there would be more registers for each id_Offer from Offer but I want to limit the example]

Таким образом, у меня есть 2 предложения в целом, с несколькими профилями в каждом из них.

Таблица Предложение выглядит примерно так:

Offer   -   business_name
1       -   business-1
2       -   business-1
3       -   business-1
4       -   business-1
5       -   business-2 
6       -   business-2 
7       -   business-2 
8       -   business-3

Поэтому, когда я делаю запрос типа

select distinct id_offer, business_name, COUNT(*)
FROM Offer
GROUP BY business_name
Order by COUNT(*);

Я получаю это для бизнеса-1 У меня есть 4 предложения.

Теперь, если я хочу принять во внимание предложения для некоторого профиля, я должен присоединиться к моим тройственным отношениям. Но даже если я сделаю так просто, как следующее

select distinct business_name
from Offer
INNER JOIN  ternary ON Offer.id_Offer = ternary.id_Offer
GROUP BY business_name
WHERE business_name =  'business-1'

Независимо от того, что я положил на группу, или, если я пишу отдельно или нет, я не получаю то, что хочу. Реальность такова, что для business-1 у меня есть 4 предложения. Прямо сейчас в тройном появятся только два. Поэтому он должен вернуть 2 уникальных предложения для этого имени без фильтрации по профилю.

Но вместо этого я получаю 8 предложений, потому что это то, сколько раз он появляется в тройном, id_Offer, который соответствует.

Как это сделать? Если мне не нужны фильтры, я могу просто взглянуть на таблицу предложений. Но что, если мне нужно отфильтровать id_skill или id_Profile И хотите вернуть бизнес-имя?

Я видел такие решения, как это, но я не могу заставить их работать, я не понимаю, что ? как это называется, чтобы узнать больше об этом, если MariaDB работает одинаково в этом смысле, я не мог найти информацию об этом, потому что я не знаю, как называется эта операция. Когда я пытаюсь построить этот запрос для своих данных, я получаю:

ERROR 1064 (42000): You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near '? ORDER BY COUNT(*) DESC' at line 1

Но, как я уже сказал, трудно найти "?". как... Оператор? Функция?

  • 0
    Столбцы данных примера не соответствуют столбцам запроса.
  • 2
    Вы редко сочетаете GROUP BY с SELECT DISTINCT, потому что GROUP BY устраняет дубликаты.
Показать ещё 4 комментария
Теги:
mariadb
join

2 ответа

1
Лучший ответ

Существует два основных решения.

SELECT
  o.business_name,
  COUNT(DISTINCT o.id_offer)   AS unique_offers
FROM
  Offer     AS o
INNER JOIN
  ternary   AS t
    ON t.id_Offer = o.id_Offer
WHERE
      o.business_name = 'business-1'
  AND t.id_profile IN (1, 2, 3, 5)
GROUP BY
  o.business_name

Это самый простой способ написать и подумать. Но это также может быть довольно интенсивным, потому что вы все еще присоединяетесь к каждой строке, offer 4 строки в ternary Создание 8 строк для агрегирования и обработки через DISTINCT.

"Лучше" (на мой взгляд) маршрут состоит в том, чтобы затем фильтровать совокупность ternary таблицы в подзапросе.

SELECT
  o.business_name,
  COUNT(*)         AS unique_offers
FROM
  Offer     AS o
INNER JOIN
(
  SELECT id_Offer
    FROM ternary
   WHERE id_profile IN (1, 2, 3, 5)
GROUP BY id_Offer
)
  AS t
    ON t.id_Offer = o.id_Offer
WHERE
  o.business_name = 'business-1'
GROUP BY
  o.business_name

Это гарантирует, что t только когда-либо имеет один ряд для любого данного предложения. Это, в свою очередь, означает, что каждая строка, offer только когда-либо, присоединяется к одной строке в t; нет дублирования. Это, в свою очередь, означает, что нет необходимости использовать COUNT(DISTINCT) и снимает некоторые накладные расходы (переместив его во внутренний запрос GROUP BY).

  • 0
    Если я удалю фильтр из профиля, я получу номер, который должен получить. Замечательно!! Теперь у меня есть вопрос, и это, вероятно, связано с моими данными, но ... Почему, если я фильтрую по каждому профилю, один за другим, сумма COUNT будет больше, чем когда я не фильтрую по профилю в подзапросе и только фильтр по business_name (имеется в виду: предположим, я хочу предложения от ВСЕХ профилей. Если я уберу фильтр профиля, это то, что я должен получить правильно? Но цифры не совпадают).
  • 1
    @monkeyintern - потому что id_offer == 1 включен в профили 1 и 2. А id_offer == 2 включен в профили 1 и 3 и 5. Так что нет, они не должны складываться ... Offers_For_Profile_1 (2) + Offers_For_Profile_2 (1) будет выше, чем Offers_For_Profile_1_Or_2 (2) ...
Показать ещё 2 комментария
0

Вы говорите, что хотите видеть предложения для определенного бизнеса, но вы хотите ограничить их в соответствии с определенными профилями или навыками?

Мы ограничиваем результаты запроса в WHERE. Если мы хотим искать данные в другой таблице, мы используем IN или EXISTS. Например:

select *
from offer
where business_name = 'business-1'
and id_offer in
(
  select id_offer
  from ternary
  where id_profile = 1
    and id_skill = 2
);

Ещё вопросы

Сообщество Overcoder
Наверх
Меню