Определить, существует ли комбинация записей «многие ко многим»

#php #mysql #many-to-many #innodb

#php #mysql #»многие ко многим» #innodb

Вопрос:

Кажется, что это была бы обычная задача с простым решением, но я столкнулся с пустыми руками как в StackOverflow, так и в Google.

Сценарий таков: у меня есть две таблицы A amp; B, которые имеют отношение «многие ко многим». Таким образом, у меня есть таблица A_B с внешними ключами, которая отображает отношения записей A-to-B. Стандартный материал.

Все, что я пытаюсь выяснить, это как запрашивать таблицы перед вводом новой записи (одна запись «A» с одной или несколькими записями «B»), если совпадающая идентичная связь уже существует. Цель состоит в том, чтобы не дублировать данные.

Наконец, эти таблицы станут довольно большими, поэтому мне нужно снизить накладные расходы там, где это вообще возможно.

Обновить

Ниже приведен пример запроса, который я пытался выполнить, чтобы определить, существует ли существующая запись A, сопоставленная значениям B_id 3, 4 и 5. Это работает, однако возвращает ложные срабатывания, если есть два разных значения A_id, которые охватывают 3, 4 и 5, например:

  • Значения A_id = 1, B_id = 2, 3
  • Значения A_id = 2, B_id = 4, 5, 6
 SELECT A_id, B_id
FROM A_B
GROUP BY
A_id HAVING
    B_id IN (3,4,5)
    AND
    COUNT(*) = 3
LIMIT 1
  

ОБНОВЛЕНИЕ 2

Первичный ключ таблицы A_B является составным ключом, включающим A_id и B_id.

Таблица A_B определяет уникальный составной ключ, включающий A_id и B_id.

Один A состоит из одного или нескольких Bs.

Более общий способ сформулировать этот вопрос: учитывая конечный набор значений идентификатора B, мне нужно иметь возможность определить, существует ли существующее A, состоящее из этого точного набора Bs. Если нет, создается новый A с этим набором Bs.

Приветствия

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

1. Вы хотите сказать, что, хотя отношение A_B является отношением «многие ко многим», только одной записи A разрешено относиться к определенному подмножеству записей B?

2. Извините, до сих пор не обращал внимания на ваш вопрос. Это правильно. Бизнес-логика диктует, что A состоит из 1 или более Bs.

Ответ №1:

У вас действительно есть внешние ключи? Должен быть способ объявить эту комбинацию table1.key->table2.key уникальной. Что привело бы к обычной ошибке SQL при создании уже существующей пары записей. Это то, что мне нравится в внешних ключах. Это очень чисто, потому что информация о (не) разрешенных записях остается на уровне базы данных.

У вас есть таблица A_B, содержащая назначения, не так ли? A.id 88 принадлежит B.id 99 … и т.д.?

И вы планируете вставить ОДНУ A-запись в сочетании с n B-записями? Почему бы и нет — если новые значения равны A = 99 и B: 10, 11, 12, 17, 18, 20

 SELECT b_id
FROM A_B
WHERE a_id = 99
AND b_id IN (10, 11, 12, 17, 18, 20);
  

В результате получится список b_id, который вы не должны вставлять повторно … Или пустой результат (все записи новые).

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

1. Спасибо. Да, у меня действительно есть внешние ключи. Да, от одной записи A до n записей B. Проблема с вашим запросом заключается в том, что, если есть запись A = 99 и B записывает 10,11,12,17,18,20 и 21 , запрос вернет ложноположительный результат. Значения идентификатора B должны быть уникальными. Я добавил больше к своему вопросу, возможно, это поможет прояснить ситуацию.

2. @Heiko, еще одна вещь, вы сказали «Должен быть способ объявить эту комбинацию table1.key->table2.key уникальной». Это нарушило бы связь «многие ко многим», разделяемую между таблицами A и B.

3. УНИКАЛЬНОСТЬ для внешнего ключа будет означать не уникальные записи в A и B, а уникальные комбинации A-> B. Я не понимаю проблемы с существующими 21, если вы собираетесь добавить 10,11,12,17,18,20. Если существуют A= 99 —> B= 10,11,12,17,18,20, 21 , вашим результатом будет [10,11,12,17,18,20] значения, которые вы не должны вставлять. Может быть, я все еще что-то неправильно понял?

4. @Heiko — Eesh, уникальный A<—>B правильный. Два столбца таблицы A_B содержат ее первичный ключ. Извините. Проблема в том, что мы не знаем «99». Мы знаем только «вот новый набор значений B. Существует ли существующее A, состоящее из этих и только этих значений B?» Я обновлю свой первоначальный вопрос.

5. Хорошо, теперь я понимаю ваше утверждение SQL в вашем вопросе. Но он предоставляет A-значения, которые объединяются с 3, или 4, или 5, потому что count (*) ссылается на внешний запрос. с подвыборкой проблем быть не должно. Думая о чем-то, без чего подвыборки — отстой!

Ответ №2:

Почему бы просто не запросить таблицу, чтобы узнать, существуют ли существующие записи?

 $query = "SELECT * from tableA_B WHERE columnA = A"
$result = mysql_query($query);
if( mysql_num_rows($result) > 1){
    //do something about having entries
}
  

Очевидно, что вам придется заменить имена таблиц и столбцов фактическими значениями, а также ваш параметр поиска для A.

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

1. Это то, что я спрашиваю, как сделать. Я обновлю свой вопрос с «как определить» на «как запрашивать таблицы», я думаю, это неясно.

2. Спасибо, но я говорю об уникальной взаимосвязи между записью в таблице A и несколькими записями в таблице B. Ваш код не решает проблему.

3. @Madbreaks — если существует определенное значение A, с которым связано несколько записей B, то запрос вернет все строки, каждая с другим значением B, но с тем же значением A. Если на момент запроса существует только отношение «один к одному», то будет возвращена только одна строка.

4. @DShook — Я думаю, что ваш подход слишком черно-белый: «могу ли я вставить все значения? Или ни одной «. На самом деле могут возникнуть ситуации типа «вставьте 3, оставьте 2 из них!»

5. @DShook — вот пример двух уникальных сопоставлений: A=1, B = 1,2 (и) A =1, B = 1,2,3. Это разные сопоставления, но ваш запрос обрабатывает их одинаково.

Ответ №3:

GROUP_CONCAT спешит на помощь! Учитывая значения B_id 1, 3 и 5, вот как вы (я) можете определить, существует ли эта уникальная комбинация, и одновременно получить соответствующий A_id:

 SELECT A_id FROM A_B
GROUP BY A_id
HAVING GROUP_CONCAT(B_id) = '1,3,5';
  

Никаких подзапросов не требуется, и их можно оптимизировать, добавив составной индекс A_id_B_id в таблицу A_B.

Спасибо участникам, которые вмешались и в конечном итоге направили меня в правильном направлении.

Приветствия