2012-04-25 130 views
4

我有3个表。寻找一种使用三个不同表格找到字段PRICE的差异的好方法,然后显示前三个最大的负面差异。我想先找到最好的MySQL查询使用,并找到最好的方式来显示它在PHP中。联盟选择MySQL的查询,做数学和显示在PHP

MAINTABLE:

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

COMPTABLE1:

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

COMPTABLE2:

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

所以在价格上,我想显示在我的网页上最大的负面差异:

  1. Competitor2 ProductD从主要公司ProductD -200差异
  2. Competitor1 ProductD从主要-100差公司ProductD
  3. Competitor2产品B -6从主要产品B公司

IDEA区别:我不是那么亲切,但我可​​以在三张桌子WHERE MODEL=XXX上使用.. UNION SELECT。我可能会循环每一个收集数据,做数学和吐出信息。唯一的问题是,我不知道如何将每个变量存储为每个表的自己的价格。另外,我认为它会显示所有的差异,除非在数学计算之后存储每个变量,然后显示前三个差异。

任何想法或建议,以最好地解决这个问题将不胜感激。 (注意:不,我不能把它们全部放在一张表中= p)

回答

5

在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个竞争对手,则查询完全相同。

+0

美丽。到目前为止,它在我执行的所有测试中都能正常工作,谢谢。 – ToddN 2012-04-25 17:14:03

+0

ahem - 我的解决方案下面更灵活,更高效... – mson 2012-04-25 17:27:31

+1

@ToddN,虽然这适用于所有产品,如果你想要一个特定的单一模型的竞争对手名单,我只是将其添加为WHERE子句每个联盟......或者,如果你想要每个型号的前3名,那也是一个不同的查询。 – DRapp 2012-04-25 17:41:20

0

在mysql中进行繁重的计算是个坏主意。在我们的项目中,我们很难优化MySQL游戏的一部分。最好的决定是用php代码然后在mysql中计算硬数学。所以在你的地方,我想在PHP中编写代码,并只使用mysql进行简单查询和一些连接。

1
SELECT CASE WHEN C1.Price<C2.Price THEN C1.COMPANY ELSE C2.COMPANY END AS company, 
     M.Model, 
     CASE WHEN C1.Price<C2.Price THEN C1.Price-M.Price ELSE C2.Price-M.Price END AS diff 
FROM MAINTABLE M, COMPTABLE1 C1, COMPTABLE2 C2 
WHERE M.Model=C1.Model AND M.Model=C2.Model 
ORDER BY diff ASC 
LIMIT 3 
1
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,或甲骨文会。您可以在此处进行优化的一件事是确保价格列是数字,并且模型列是在每个表中建立索引的。

偏离主题 - 但是当你听说谷歌使用mysql时 - 他们拥有优化其系统的dba gurus团队。使用sql server express(免费)或postgres(开源)的小型商店可能会更好。

+0

是的,你可能看起来更有效率,但是,你的内部查询工会公司,模型和价格,但可以得到性能击中没有利用派生/联盟表上的索引。在某些情况下,我也会按照你在这里的路线走一个联盟的路线,但只有当一个已知的标准阻止一个完整的表加入一个完整的表。尊重意见分歧,但肯定会起作用。 – DRapp 2012-04-25 17:34:55

+0

好点的drapp。如果派生表成为性能问题,我会创建一个索引视图。真的看起来2个客户桌子的设计不正确,无论如何都应该是单个桌子。 – mson 2012-04-25 17:49:19