Выберите все из A и объедините все неповторяющиеся комбинации из B так, чтобы: ab, ac, ad, abc, abd ... в MySQL? - PullRequest
1 голос
/ 13 октября 2011

У меня есть стол A с продуктами питания.

У меня есть стол B с пищевыми добавками.

Таблица B имеет поля:

  • цена
  • добавленные_калории
  • имя
  • продукты

Я хочусделайте такой запрос, чтобы получить 10 лучших (или более) комбинаций продуктов и дополнений, которые приведут к наилучшему соотношению калорий / цена .Мне нужно сохранить имена дополнений и продукта для отображения пользователю.

У меня должно быть несколько дополнений на 1 продукт, чтобы я могпопробуйте пройти через все комбинации.

Если у нас есть аддоны a , b , c , d , тогда я должен попробовать комбинации:

  • Продукт + a
  • Продукт + b
  • Продукт + ab
  • Продукт + ac
  • Продукт + объявление
  • Product + bc
  • Product + bd
  • ...

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

1 Ответ

4 голосов
/ 13 октября 2011

Предполагая, что вы хотите максимизировать калории / цену, я думаю, что можно выполнимо. Хитрость заключается в том, что для конкретного продукта вы максимизируете калории / цену, накапливая надстройки в порядке убывания соотношения калорий / цены, пока общее соотношение не начнет уменьшаться.

Следующий запрос, вероятно, смехотворно неэффективен и нуждается в серьезной оптимизации, но, по крайней мере, показывает, что решение существует:

SELECT
  p.name AS product,
  GROUP_CONCAT(a.name) AS additives,
  p.price + COALESCE(SUM(a.price), 0) AS price,
  p.calories + COALESCE(SUM(a.added_calories), 0) AS calories,
  (p.calories + COALESCE(SUM(a.added_calories), 0)) /
    (p.price + COALESCE(SUM(a.price), 0)) AS calories_per_price
FROM
  products AS p
  LEFT JOIN connector AS c ON c.product = p.id
  LEFT JOIN additives AS a
    ON a.id = c.additive
    AND (a.added_calories / a.price) > (
      (p.calories + COALESCE((
        SELECT SUM(b.added_calories) FROM connector AS d, additives AS b
        WHERE d.product = p.id AND b.id = d.additive
          AND (b.added_calories / b.price) > (a.added_calories / a.price)
      ), 0)) /
      (p.price + COALESCE((
        SELECT SUM(b.price) FROM connector AS d, additives AS b
        WHERE d.product = p.id AND b.id = d.additive
          AND (b.added_calories / b.price) > (a.added_calories / a.price)
      ), 0))
    )
GROUP BY p.id
ORDER BY calories_per_price DESC
LIMIT 10;

Редактировать: ОК, я его отладил, теперь он действительно работает (!). Вот некоторые тестовые данные:

INSERT INTO products (id, name, calories, price) VALUES
  (1, 'Cardboard', 0, 1),
  (2, 'Lard', 1000, 100),
  (3, 'Spaghetti', 10, 50);
INSERT INTO additives (id, name, added_calories, price) VALUES
  (1, 'Salt', 0, 2),
  (2, 'Butter', 500, 100),
  (3, 'Cheese', 300, 70),
  (4, 'Pepper', 0, 3),
  (5, 'Ketchup', 50, 10),
  (6, 'Milk', 20, 10);
INSERT INTO connector (product, additive) VALUES
  (1,1), (1,2), (1,3), (1,4), (1,5), (1,6),
  (2,1), (2,3), (2,4), (2,5),
  (3,1), (3,2), (3,3), (3,4), (3,5);

И результаты:

+-----------+-----------------------+-------+----------+--------------------+
| product   | additives             | price | calories | calories_per_price |
+-----------+-----------------------+-------+----------+--------------------+
| Lard      | NULL                  |   100 |     1000 |                 10 | 
| Cardboard | Butter,Ketchup        |   111 |      550 |   4.95495495495495 | 
| Spaghetti | Butter,Cheese,Ketchup |   230 |      860 |   3.73913043478261 | 
+-----------+-----------------------+-------+----------+--------------------+

Редактировать 2: Упс, у меня была максимальная цена за калории вместо калорий за цену. Исправлено.

Редактировать 3: Подзапросы игнорировали таблицу соединителей. Я (надеюсь) исправил эту ошибку, но пока не смог ее проверить.

...