如何使用2个表优化查询?

时间:2013-12-18 20:22:00

标签: mysql sql

大家好,我有一个很长的查询,我试图用更少的单词减少它并尝试优化它。

这是我的问题:

SET @year := 2013;
SET @euro := 3.14;

SELECT
SUM(IF (CONCAT(@year, '-01') BETWEEN date_format(date_ini, '%Y-%m') AND date_format(date_expired, '%Y-%m'),i.net_insurance * IF (type_money = 2, @euro, 1), 0)) Jan,
SUM(IF (CONCAT(@year, '-02') BETWEEN date_format(date_ini, '%Y-%m') AND date_format(date_expired, '%Y-%m'),i.net_insurance * IF (type_money = 2, @euro, 1), 0)) Feb,
SUM(IF (CONCAT(@year, '-03') BETWEEN date_format(date_ini, '%Y-%m') AND date_format(date_expired, '%Y-%m'),i.net_insurance * IF (type_money = 2, @euro, 1), 0)) Mar,
SUM(IF (CONCAT(@year, '-04') BETWEEN date_format(date_ini, '%Y-%m') AND date_format(date_expired, '%Y-%m'),i.net_insurance * IF (type_money = 2, @euro, 1), 0)) Apr,
SUM(IF (CONCAT(@year, '-05') BETWEEN date_format(date_ini, '%Y-%m') AND date_format(date_expired, '%Y-%m'),i.net_insurance * IF (type_money = 2, @euro, 1), 0)) May,
SUM(IF (CONCAT(@year, '-06') BETWEEN date_format(date_ini, '%Y-%m') AND date_format(date_expired, '%Y-%m'),i.net_insurance * IF (type_money = 2, @euro, 1), 0)) Jun,
SUM(IF (CONCAT(@year, '-07') BETWEEN date_format(date_ini, '%Y-%m') AND date_format(date_expired, '%Y-%m'),i.net_insurance * IF (type_money = 2, @euro, 1), 0)) Jul,
SUM(IF (CONCAT(@year, '-08') BETWEEN date_format(date_ini, '%Y-%m') AND date_format(date_expired, '%Y-%m'),i.net_insurance * IF (type_money = 2, @euro, 1), 0)) Aug,
SUM(IF (CONCAT(@year, '-09') BETWEEN date_format(date_ini, '%Y-%m') AND date_format(date_expired, '%Y-%m'),i.net_insurance * IF (type_money = 2, @euro, 1), 0)) Sep,
SUM(IF (CONCAT(@year, '-10') BETWEEN date_format(date_ini, '%Y-%m') AND date_format(date_expired, '%Y-%m'),i.net_insurance * IF (type_money = 2, @euro, 1), 0)) Oct,
SUM(IF (CONCAT(@year, '-11') BETWEEN date_format(date_ini, '%Y-%m') AND date_format(date_expired, '%Y-%m'),i.net_insurance * IF (type_money = 2, @euro, 1), 0)) Nov,
SUM(IF (CONCAT(@year, '-12') BETWEEN date_format(date_ini, '%Y-%m') AND date_format(date_expired, '%Y-%m'),i.net_insurance * IF (type_money = 2, @euro, 1), 0)) `Dec`

FROM insurances  i
INNER JOIN policies p ON p.id = i.policy_id
WHERE (i.initial_date >= p.date_ini
AND i.final_date   <= p.date_expired)

这是我的结果:

JAN      FEB    MAR      APR    MAY      JUN    JUL      AUG    SEP      OCT    NOV     DEC
20286   20286   26496   26496   26496   26496   26496   26496   9936    9936    9936    9936

以下是我的演示:http://sqlfiddle.com/#!2/074ff/1

请有人帮助我吗?

我真的很感激帮助。

2 个答案:

答案 0 :(得分:2)

这是您的另一种选择。

由于@sqlvars的创建,这可能会持续一段时间,但它应该在几个方面有所帮助。

第一个FROM(创建sqlvars的子选择)除了创建12个表示每月Jan-Dec的“dt”日期的简单变量作为日期格式之外什么都不做,我们摆脱了每个字符串连接。记录日期和相应的起始日期。

第二个FROM(子选择仅查询有关日期范围的那些合格记录,但是当它在那里时,它会将@euro因子计算为最终列名“InsAmount”。

最后,合并在一起的那些简化了SUM()聚合可读性因子。

SET @euro := 3.14;

SELECT
      SUM( IF ( @dtJan BETWEEN date_ini AND date_expired, InsAmount, 0)) Jan,
      SUM( IF ( @dtFeb BETWEEN date_ini AND date_expired, InsAmount, 0)) Feb,
      SUM( IF ( @dtMar BETWEEN date_ini AND date_expired, InsAmount, 0)) Mar,
      SUM( IF ( @dtApr BETWEEN date_ini AND date_expired, InsAmount, 0)) Apr,
      SUM( IF ( @dtMay BETWEEN date_ini AND date_expired, InsAmount, 0)) May,
      SUM( IF ( @dtJun BETWEEN date_ini AND date_expired, InsAmount, 0)) Jun,
      SUM( IF ( @dtJul BETWEEN date_ini AND date_expired, InsAmount, 0)) Jul,
      SUM( IF ( @dtAug BETWEEN date_ini AND date_expired, InsAmount, 0)) Aug,
      SUM( IF ( @dtSep BETWEEN date_ini AND date_expired, InsAmount, 0)) Sep,
      SUM( IF ( @dtOct BETWEEN date_ini AND date_expired, InsAmount, 0)) Oct,
      SUM( IF ( @dtNov BETWEEN date_ini AND date_expired, InsAmount, 0)) Nov,
      SUM( IF ( @dtDec BETWEEN date_ini AND date_expired, InsAmount, 0)) `Dec`
   from 
      ( select 
              @dtJan := '2013-01-01',
              @dtFeb := DATE_ADD( @dtJan, INTERVAL 1 MONTH ),
              @dtMar := DATE_ADD( @dtFeb, INTERVAL 1 MONTH ),
              @dtApr := DATE_ADD( @dtMar, INTERVAL 1 MONTH ),
              @dtMay := DATE_ADD( @dtApr, INTERVAL 1 MONTH ),
              @dtJun := DATE_ADD( @dtMay, INTERVAL 1 MONTH ),
              @dtJul := DATE_ADD( @dtJun, INTERVAL 1 MONTH ),
              @dtAug := DATE_ADD( @dtJul, INTERVAL 1 MONTH ),
              @dtSep := DATE_ADD( @dtAug, INTERVAL 1 MONTH ),
              @dtOct := DATE_ADD( @dtSep, INTERVAL 1 MONTH ),
              @dtNov := DATE_ADD( @dtOct, INTERVAL 1 MONTH ),
              @dtDec := DATE_ADD( @dtNov, INTERVAL 1 MONTH ) ) sqlvars,
      ( select
              date_ini,
              date_expired,
              i.net_insurance * IF (type_money = 2, @euro, 1) as InsAmount
           from
              insurances  i
                 INNER JOIN policies p ON i.policy_id = p.id
           WHERE 
                  i.initial_date >= p.date_ini
              AND i.final_date   <= p.date_expired ) as QryRecs

答案 1 :(得分:1)

您正在尝试进行数据透视查询,MySQL不支持。正如您所看到的,解决方法变得非常难看,非常快。

您唯一的选择是切换到支持PIVOT查询的DBMS,或者在没有所有条件列逻辑的情况下恢复到传统的SELECT ... FROM ...查询,并执行rows-&gt;列转换在您的客户端代码中。