MySQL加入改进

时间:2011-09-23 15:47:59

标签: mysql sql

我无法让MySQL正确地返回查询。

这是我的数据:

id            date            value
2             2011-01-04         55.66
2             2011-03-23         22.33
2             2011-04-21          9.44
5             2010-01-04        104.55
5             2011-02-03         38.82
...              ...              ...

我正在尝试返回一个查询:

select t1.id, max(t1.date), t1.value, t2.id, min(t2.date), t2.value
from tab1 as t1, tab1 as t2
where t1.id = t2.id
and t1.date <= '2011-03-31'
and t2.date >= '2011-04-01'
group by t1.id;

但这是永远的(db有~1mm线)。我尝试了各种连接但是它似乎忽略了日期&lt;和&gt;声明。基本上我希望每个客户在2011年4月1日之前的最后购买日期和金额以及他们在2011年4月1日或之后的首次购买和日期。任何建议都会很棒。

4 个答案:

答案 0 :(得分:1)

SELECT t2.* 
FROM tab1 t2
INNER JOIN  
(SELECT t1.id,
MIN(CASE WHEN t1.date>='2011-04-01' THEN t1.date END) as min_date_1,
MAX(CASE WHEN t1.date<='2011-03-31' THEN t1.date END) as max_date_2
SUM(CASE WHEN t1.date>='2011-04-01' THEN t1.value END) sum_1,
SUM(CASE WHEN WHEN t1.date<='2011-03-31' THEN t1.value END) sum_2
FROM tab1 t1
GROUP BY t1.id)a ON 
(a.id = t2.id AND (t2.date = a.min_date_1 OR t2.date = a.max_date_2))

假设您有索引(id,date),它应该可以很快地工作。

更新添加总和

答案 1 :(得分:1)

您的查询存在缺陷,列t1.value和max(t1.date)与one和other之间没有关系。

如果您想知道所选日期的总购买量,您需要按如下方式重写。

SELECT st1.id, st1.date, st1.total_value, st2.id, st2.date, st2.total_value
FROM (SELECT t1.id, t1.date, sum(t1.value) as total_value
      FROM tab1 t1
      WHERE t1.date <= '2011-03-31'
      GROUP BY t1.id
      HAVING t1.date = MAX(t1.date)
      ) st1
INNER JOIN (SELECT t2.id, t2.date, sum(t2.value) as total_value
           FROM tab1 t2
           WHERE t2.date > '2011-03-31'
           GROUP BY t2.id
           HAVING t2.date = MAX(t2.date)
           ) st2 
  ON (st1.id = st2.id)

确保您在iddate

上有索引

<强>说明
id通常被理解为主键的简写 有一个名为id的字段一个唯一索引,令人困惑,并被广泛认为是代码气味。

答案 2 :(得分:1)

SELECT
      td.id
    , ta.`date` AS before_date
    , ta.value AS value_at_before_date
    , tb.`date` AS after_date
    , tb.value AS value_at_after_date
FROM
    ( SELECT DISTINCT id
      FROM tabl
    ) AS td
  LEFT JOIN
    tabl AS ta
      ON ta.tablePK =   
        ( SELECT tablePK
          FROM tabl AS a 
          WHERE `date` < '2011-04-01'
            AND a.id = td.id
          ORDER BY `date` DESC
          LIMIT 1
        ) 
  LEFT JOIN
    tabl AS tb
      ON tb.tablePK =   
        ( SELECT tablePK
          FROM tabl AS b 
          WHERE `date` >= '2011-04-01'
            AND b.id = td.id
          ORDER BY `date` ASC
          LIMIT 1
        ) 

其中tablePK是表格的PRIMARY KEY(我希望你有一个)。

(id, date, tablePK)上的索引对速度有帮助。

答案 3 :(得分:1)

数据 - 查询生成一些测试数据,而不是创建表保持测试数据。

before_query - 检索每个客户ID的最长日期&lt; = 2011-03-31

after_query - 为每个客户ID检索最小日期&gt; = 2011-04-01

除了使用Oracle的虚拟dual表(我用它来生成一些测试数据)之外,我相信我只使用了标准的SQL语法。

您不需要生成数据,因此可以省略部分查询。在查询中引用data的任何地方,请将其替换为table name

with
    data as (select 2 as id, '2011-01-04' as trans_date, 55.66 as value from dual
                    union all
             select 2 as id, '2011-03-23' as trans_date, 22.33 as value from dual
                    union all
             select 2 as id, '2011-04-21' as trans_date, 9.44 as value from dual
                    union all
             select 5 as id, '2010-01-04' as trans_date, 104.55 as value from dual
                    union all
             select 5 as id, '2011-02-03' as trans_date, 38.82 as value from dual),

    before_qry as (select id, max(trans_date) as max_date from data
                   where trans_date <= '2011-03-31'
                   group by id),

    after_qry as (select id, min(trans_date) as min_date from data
                   where trans_date >= '2011-04-01'
                   group by id)

    select bq.*, bq_d.value, aq.*, aq_d.value
    from before_qry bq inner join after_qry aq on bq.id = aq.id
    inner join  data bq_d on bq.id = bq_d.id and bq.max_date = bq_d.trans_date
    inner join data aq_d on aq.id=aq_d.id and aq.min_date = aq_d.trans_date

对于您的问题中显示的测试数据,此查询提供以下结果

        ID MAX_DATE        VALUE         ID MIN_DATE        VALUE
---------- ---------- ---------- ---------- ---------- ----------
         2 2011-03-23      22.33          2 2011-04-21       9.44