Есть ли способ ответить на этот вопрос в одном запросе? - PullRequest
0 голосов
/ 03 апреля 2011

У меня есть база данных MySQL из 3 таблиц:

I. Персона (идентификатор, имя, покупки)II. Покупка (id, продукт, дата_куплена)III. Каталог (идентификатор, продукт, цена за единицу)

Персона .purchases удерживает Purchase.id.То есть каждый раз, когда человек что-то покупает, идентификатор заказа записывается в Person.purchases.Например,В Person.purchases хранится 1 300 300 292.

Каждая запись Покупка регистрирует экземпляр любого приобретенного предмета.Итак, Purchase.id = 300 может быть "foo".

И Каталог содержит описание "foo".

Что я хочу узнать, так это как ответить: "Кто купил" foo "? Я знаю, как ответить на этот вопрос в 2 этапа следующим образом:

Шаг 1: ВЫБРАТЬ Buyases.id ИЗ ПРИЛОЖЕНИЙ ВНУТРЕННИЙ ПРИСОЕДИНЯЙТЕСЬ К КАТАЛОГУ ГДЕ Покупки.product =Catalog.product;

Я бы сохранил результат шага 1 в переменной tmp ;

STEP 2: ВЫБЕРИТЕ имя ОТ ЛИЦА, ГДЕ Person.ordersLIKE "% tmp %";

Я использую LIKE выше, потому что Person.orders хранит несколько Purchase.id.

Есть ли способобъединить эти два в один запрос?

Ответы [ 4 ]

2 голосов
/ 03 апреля 2011

На вопрос можно ответить, используя один запрос:

Использование EXISTS

SELECT a.name
  FROM PERSON a
 WHERE EXISTS(SELECT NULL
                FROM PURCHASE b 
                JOIN CATALOG c ON c.product = b.product
               WHERE FIND_IN_SET(b.id, a.purchases) > 0
                 AND c.product = 'foo')

Использование JOIN:

Для этого требуется DISTINCT (или GROUP BY), поскольку возможны дубликаты, если человек / клиент купил «foo» более одного раза.

SELECT DISTINCT a.name
  FROM PERSON a
  JOIN PURCHASE b ON FIND_IN_SET(b.id, a.purchases) > 0
  JOIN CATALOG c ON c.product = b.product
 WHERE c.product = 'foo'

Добавление

Я согласен с другими ответами, что модель данных плохая - в таблице ПОКУПКА должен быть идентификатор человека / клиента, а не таблица PERSON. Но это ничего не меняет кардинально.

2 голосов
/ 03 апреля 2011

Это плохой дизайн базы данных, и он удерживает вас от ответа на относительно простой вопрос.Я бы разработал ваши таблицы примерно так:

customers (id, name)
purchases (id, product_id, customer_id, date_purchased)
products (id, product_name, cost_per_unit)

Таким образом, ваш запрос, чтобы выяснить 'Кто купил foo?'Это:

SELECT c.id, c.name
FROM products pr 
   LEFT JOIN purchases pu ON (pr.id = pu.product_id)
   INNER JOIN customers c ON (pu.customer_id = c.id)
WHERE product_id = foo 
-- could replace with product_name = 'foo' here, but you should know product_id

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

Этоздесь также может быть полезно создать другую таблицу, назовите ее receipts и переименуйте purchases в line_items.Это гарантирует, что вы можете отслеживать клиентов, которые покупают несколько товаров за одну покупку и т. Д.

1 голос
/ 03 апреля 2011

Для MySQL это может быть лучшим решением:

SELECT person.*
FROM person
JOIN purchases
ON FIND_IN_SET(purchases.id,person.purchases) > 0
WHERE purchases.product = 'foo';
1 голос
/ 03 апреля 2011

Гораздо лучшая структура ваших таблиц будет:

I. Персона (personid, имя) --- покупки удалены отсюда

II. Покупка (идентификатор покупки, идентификатор покупателя, продукт, дата покупки) --- добавлен идентификатор покупателя

III. Каталог (продукт, продукт, цена за единицу)

Таким образом, вместо хранения покупок человека в таблице Person, сохраните их в таблице покупок.

Thisбудет иметь несколько преимуществ:

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

  2. Проще писать свои запросы.


(Если в Person.purchases есть ", 1,300,292," сохраненные в нем, например, запятые в начале и конце поля и без пробелов), на ваш вопрос можно ответить одним запросом:1031 * Если в начале и в конце есть пробелы и нет запятых, условие будет более сложным, но, безусловно, это можно сделать.

SELECT p.id, p.name
FROM Person p
  JOIN Purchase pur
    ON p.purchases LIKE CONCAT("%,",CAST(pur.id AS CHAR),",%")
WHERE pur.product LIKE "foo"

И объединение с Catalog не требуется, поскольку Product имя тоже в таблице Purchase.

Если вы хотите получить информацию от Catalog, вы можете использовать и другое соединение:

SELECT p.id, p.name, cat.*
FROM Person p
  JOIN Purchase pur
    ON p.purchases LIKE CONCAT("%,",CAST(pur.id AS CHAR),",%")
  JOIN Catalog cat
    ON pur.product = cat.product
WHERE pur.product LIKE "foo"     ---or cat.product LIKE "foo"
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...