UNION SELECT Запрос MySQL, выполнение математических операций и отображение в PHP

У меня 3 стола. Ищите хороший способ найти разницу в поле PRICE с помощью трех разных таблиц, а затем отобразить 3 самых больших отрицательных разницы. Я хочу сначала найти лучший запрос MySQL для использования, а также найти лучший способ отобразить все это в php.

ОБСЛУЖИВАЕМЫЙ:

COMPANY       | MODEL    | PRICE
Main Company  | ProductA | 100.00
Main Company  | ProductB | 50.00
Main Company  | ProductC | 25.00
Main Company  | ProductD | 300.00

СОВМЕСТИМОСТЬ1:

COMPANY     | MODEL    | PRICE
Competitor1 | ProductA | 100.00 //0
Competitor1 | ProductB | 55.00 //5
Competitor1 | ProductC | 50.00 //25
Competitor1 | ProductD | 200.00 //-100

СОВМЕСТИМО2:

COMPANY     | MODEL    | PRICE
Competitor2 | ProductA | 99.00 //-1
Competitor2 | ProductB | 44.00 //-6
Competitor2 | ProductC | 20.00 //-5
Competitor2 | ProductD | 100.00 //-200

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

  1. Продукт D конкурента2 -200 отличие от продукта D основной компании
  2. Продукт D конкурента1 -100 отличие от продукта D основной компании
  3. Конкурент2 Продукт B -6 отличие от основного продукта компании B

ИДЕЯ: я не очень хорошо с ней знаком, но я мог бы использовать ..UNION SELECT для трех таблиц WHERE MODEL=XXX. Я мог бы, возможно, просмотреть каждый из них, собирая данные, выполняя математику и выплевывая информацию. Единственная проблема в том, что я не знаю, как хранить КАЖДУЮ переменную как собственную цену для каждой из таблиц. Кроме того, я думаю, что он будет отображать ВСЕ различия, если не будет способа сохранить каждую переменную после выполнения математики, а затем отобразить 3 основных различия.

Будем признательны за любые идеи или предложения по лучшему решению этого вопроса. (Примечание: нет, я не могу поместить их все в одну таблицу = p )


person ToddN    schedule 25.04.2012    source источник


Ответы (3)


Не могу помочь на стороне PHP, но этот запрос должен дать вам то, что вам нужно. Вам нужно будет сделать союз, чтобы получить все квалифицированные результаты. Это будет иметь все столбцы, доступные и предварительно рассчитанные для вас, чтобы вы могли поместить их в простой список сетки любым способом, который вам нужен. Поскольку расчеты проводятся в сравнении с основной компанией, разница в ценах в естественном порядке сначала будет иметь наибольшее отрицательное значение, а затем станет положительным. Таким образом, команда LIMIT будет применена после заказа и просто отправит обратно 3 записи.

select 
      MT.Model,
      MT.Company as MainCompany,
      MT.Price as MainPrice,
      CT1.Company as Competitor,
      CT1.Price as CompPrice,
      CT1.Price - MT.Price as PriceDifference
   from
      MainTable MT
         JOIN CompTable1 CT1
            on MT.Model = CT1.Model
UNION
select 
      MT.Model,
      MT.Company as MainCompany,
      MT.Price as MainPrice,
      CT2.Company as Competitor,
      CT2.Price as CompPrice,
      CT2.Price - MT.Price as PriceDifference
   from
      MainTable MT
         JOIN CompTable2 CT2
            on MT.Model = CT2.Model
order by
   PriceDifference
limit 3

Предложение... То, как вы структурируете свои таблицы, действительно плохо работает в долгосрочной перспективе. Вы должны попытаться нормализовать свои данные для более оптимальной производительности. Что произойдет, если у вас есть 100 конкурентов. У вас везде дублирование. Измените также название модели. Вот как я реструктурировал бы таблицы... не явный тип данных, а концептуально

COMPANY 
   CompanyID     auto-increment
   CompanyName   character

PRODUCT
   ProductID     auto-increment
   ProductModel  character

VendorPricing
   VPriceID      auto-increment
   CompanyID     (ID pointing to company table -- to get name when needed)
   ProductID     (ID pointing to product table -- to get model name too)
   Price         actual price for this particular company and product

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

select 
      VP1.CompanyID,
      C1.CompanyName as MainCompany,
      C2.CompanyName as Competitor,
      P1.ProductModel,
      VP1.Price as MainPrice,
      VP2.Price as CompetitorPrice,
      VP2.Price - VP1.Price as PriceDifference
   from
      VendorPricing VP1

         JOIN Company C1
            on VP1.CompanyID = C1.CompanyID

         JOIN Product P1
            on VP1.ProductID = P1.ProductID

         JOIN VendorPricing VP2
            on VP1.ProductID = VP2.ProductID
           AND NOT VP1.CompanyID = VP2.CompanyID

           JOIN Company C2
              on VP2.CompanyID = C2.CompanyID

   where
      VP1.CompanyID = TheOneCompanyYouAreInterestedIn
   order by
      PriceDifference
   limit 3

Так что теперь, если у вас было 2, 5, 10 или 100 конкурентов, запрос точно такой же.

person DRapp    schedule 25.04.2012
comment
Красивый. Пока это работает на всех тестах, которые я провел, спасибо. - person ToddN; 25.04.2012
comment
@ToddN, хотя это работает для ВСЕХ продуктов, если вам нужен список конкурентов для конкретной модели, я бы просто добавил это в качестве предложения WHERE к каждому союзу ... ИЛИ, если вы хотите 3 лучших для каждой модели, это тоже будет другой запрос. - person DRapp; 25.04.2012
comment
Спасибо, я могу делать все виды ТОП-запросов с этой методологией. - person ToddN; 25.04.2012
comment
@ToddN, после обсуждения этого вопроса с другим, я решил расширить свой ответ, чтобы помочь предотвратить будущие узкие места, основанные на ваших отношениях с базой данных и о том, как вы могли бы лучше улучшить их в будущем. Взглянем. - person DRapp; 25.04.2012

select mt1.company, tt1.company, mt1.price, tt1.price, (mt1.price - tt1.price) as delta
from mt1
    -- treats tables as single table and allows you flexibility to add more later
    left join (
    select company, model, price from t1
    union
    select company, model, price from t2
    ) tt1 on tt1.model = mt1.model
order by  (mt1.price - tt1.price) 
limit 3 -- actually should be parameter to sproc

Вам нужно подумать о нулях и пропущенных значениях. Вы ничего не указали, поэтому я их тоже не обрабатывал.

Кто-то ранее упомянул плохую производительность при выполнении расчетов mysql. Это именно то, для чего были созданы базы данных. Низкая производительность mysql больше связана с тем, что он не является «умным» и автоматически создает оптимизированный план, такой как сервер sql, postgres или oracle. Одна вещь, которую вы можете сделать для оптимизации, — убедиться, что столбцы цен являются числовыми, а столбец модели проиндексирован в каждой таблице.

не по теме - но когда вы слышите о том, что Google использует mysql - у них есть команды гуру dba, которые оптимизируют свои системы. небольшие магазины, вероятно, лучше использовать SQL Server Express (бесплатно) или postgres (с открытым исходным кодом).

person mson    schedule 25.04.2012
comment
Да, ваш внутренний запрос может выглядеть более эффективным, однако ваш внутренний запрос на объединение компаний, моделей и цен может снизить производительность без использования индексов в производной/объединенной таблице. При определенных обстоятельствах я тоже пойду по пути объединения, как и вы здесь, но только при известных критериях, препятствующих объединению полной таблицы с полной таблицей. С уважением к различиям во мнениях, но я уверен, что оба варианта сработают. - person DRapp; 25.04.2012
comment
хороший момент драпп. если производная таблица становится проблемой производительности, я бы создал индексированное представление. на самом деле кажется, что две клиентские таблицы спроектированы неправильно и в любом случае должны быть одной таблицей. - person mson; 25.04.2012

Плохая идея делать тяжелые вычисления в mysql. В нашем проекте нам очень трудно оптимизировать часть mysql нашей игры. И лучшим решением было вычислить сложную математику в php-коде, а затем в mysql. Поэтому на вашем месте я хотел бы закодировать его на php и использовать mysql только для простых запросов и некоторых объединений.

person Denis Ermolin    schedule 25.04.2012