Ссылка на несколько внешних строк из одной строки

#mysql #sql

#mysql #sql

Вопрос:

Я действительно не знаю, как это называется, поэтому я не мог найти ответа.

Например, у меня есть следующие таблицы:

 Table products                        Table users
 ---------- ---------- ----------      ---------- ---------- 
| id       | name     | price    |    | username | products |
 ---------- ---------- ----------      ---------- ---------- 
| 1        | Bread    | 1.5      |    | James    | 1, 2     |
 ---------- ---------- ----------      ---------- ---------- 
| 2        | Cookies  | 2.0      |    | David    | 2, 3     |
 ---------- ---------- ----------      ---------- ---------- 
| 3        | Milk     | 1.2      |    | Paul     | 3, 1     |
 ---------- ---------- ----------      ---------- ---------- 
 

products.id является внешним ключом для users.products .

Я хотел бы получить название и цену всех продуктов Дэвида, используя запрос MySQL. Это должно вернуть следующее:

  ---------- ---------- 
| name     | price    |
 ---------- ---------- 
| Cookies  | 2.0      |
 ---------- ---------- 
| Milk     | 1.2      |
 ---------- ---------- 
 

JOIN Я думаю, эту функцию было бы лучше всего использовать, но у Дэвида может быть только 1 или 100 продуктов. Создание 100 столбцов для всех продуктов звучит не очень эффективно.

Как я могу это осознать?


В настоящее время я просто извлекаю все и фильтрую его с помощью PHP, на данный момент это не проблема, но по мере роста таблиц, я думаю, это будет очень неэффективно.

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

1. На самом деле это очень плохая модель… то, как вы храните идентификатор продуктов в таблице users, неверно

2. Дизайн 'Users' стола неправильный. Вместо того, чтобы работать над этим плохим дизайном, пожалуйста, измените дизайн

3. Я полагаю, вы имеете в виду, что users.products столбец неверен. Я знаю, что это так, но я понятия не имею, как это сделать по-другому (в настоящее время я использую JSON для PHP). Проблема в том, что продукты, которые может иметь Дэвид, различаются.

4. У вас может быть несколько строк для каждого пользователя, т.Е. По одной строке для каждого продукта в Users таблице. Вы можете поддерживать другое логическое поле, чтобы определить, какие из них в настоящее время «активны» или «применимы». Joins' в этом случае было бы намного проще. Кроме того, обновление записей также было бы проще. В случае, если в будущем вы захотите извлекать и анализировать данные из исторических записей, это тоже возможно!!!

5. Метод, который вы описываете, является довольно стандартным способом обработки отношений «многие ко многим». У вас есть промежуточная таблица, которая содержит первичные ключи каждой таблицы, к которой вы хотите присоединиться, и вы можете получить свои результаты, объединив все три таблицы вместе.

Ответ №1:

Это можно решить, изменив вашу модель данных.

 users
 ---------- ---------- 
| id       | username |
 ---------- ---------- 
| 1        | Fred     |
 ---------- ---------- 
| 2        | John     |
 ---------- ---------- 

products                       
 ---------- ---------- ----------     
| id       | name     | price    |    
 ---------- ---------- ----------  
| 1        | Bread    | 1.5      |   
 ---------- ---------- ----------  
| 2        | Cookies  | 2.0      |  
 ---------- ---------- ----------    
| 3        | Milk     | 1.2      |  
 ---------- ---------- ----------  
 

И здесь происходит волшебство: вы можете соединить две таблицы, используя третью таблицу:

 user_procuct_connections
 ---------- ---------- ------------     
| id       | user_id  | product_id |    
 ---------- ---------- ------------  
| 1        | 1        | 2          |   ->  Fred has Cookies
 ---------- ---------- ------------  
| 2        | 1        | 3          |   ->  Fred also has Milk
 ---------- ---------- ------------    
| 3        | 2        | 1          |   ->  John has Bread
 ---------- ---------- ------------ 
 

Если вы хотите, чтобы пользователь мог владеть только одним продуктом, тогда вы можете удалить столбец id user_id и product_id создать первичный ключ вместе.

Затем, когда вы хотите получить, например, все продукты Freds, тогда просто

 SELECT 
    * 
FROM
    products
WHERE
    id IN (
    SELECT 
       product_id 
    FROM 
       user_procuct_connections 
    WHERE 
       user_id = 1
)
 

Ответ №2:

Вы могли бы попробовать это:

 SELECT * FROM products pt
where FIND_IN_SET(pt.id,(select us.prices from users us 
WHERE us.username = "David"));
 

Рабочая скрипка: http://sqlfiddle.com /#!2/4f78d/2

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

1. Спасибо, это было на самом деле то, что я искал! Тем не менее, я буду использовать решение Сатвика Надкарни, потому что таким образом проще добавлять и удалять продукты.

Ответ №3:

Дизайн таблицы «Пользователи» неправильный. Вместо того чтобы обходить этот плохой дизайн, пожалуйста, измените его.

Настолько эффективно, что ваш дизайн мог бы быть таким:

Столовые Продукты :

  ID        Name      Price
 1         Bread     1.5
 2         Cookies   2.0
 3         Milk      1.2
 

Пользователи таблицы :

  Username  Products

  James       1
  James       2
  David       2
  David       3
  Paul        3
  Paul        1
 

Видите ли, у вас может быть несколько строк для каждого пользователя, т.Е. По одной строке для каждого продукта в таблице Users. Вы можете поддерживать другое логическое поле, чтобы определить, какие из них в настоящее время «активны» или «применимы». В этом случае Joins было бы намного проще. Кроме того, обновление записей также было бы проще. В случае, если в будущем вы захотите извлекать и анализировать данные из исторических записей, это тоже возможно!!!

Еще одна особенность текущего дизайна заключается в том, что вам снова и снова придется обходить печально известные «значения, разделенные запятыми». Допустим, у вас есть запись как таковая:

  Username     Products

  James        1, 2, 3, 4, 5, 6, 7, 8, 9, 10
 

Если вам нужно отсортировать эти данные по строкам, вам придется много раз обходить значения, разделенные запятыми. Представьте, что вы делаете это для ‘n’ количества записей!!

Надеюсь, это поможет!!!

Ответ №4:

Если вы присоединитесь к таблицам, как:

 SELECT name, price FROM products AS p INNER JOIN user_products AS up ON up.id = p.product_id AND up.user_id = <davids id>
 

Вы получите массив, в котором первый столбец будет именем, а второй — ценой. Затем вы можете делать с ним все, что хотите, в PHP и изменять массив. Вам больше не нужно фильтровать.