2016-11-18 8 views
0

大規模なデータセットで動作する合理的に簡単なクエリがあります。()とdateaddの間のmysqlの相違

IN演算子を使用すると、正しい結果が得られます。
DATE_ADD()を使用すると、私は間違っていると思われる結果を得ます。

SELECT 
    e.date, er.ratio, e.total as recalc 
FROM 
    equity e 
     JOIN 
    exchange_rate er ON e.date = er.date 
     AND LOWER(er.currency) = LOWER(e.currency) 
    join account a 
     on e.account = a.id 
WHERE 
    -- e.date >= DATE_ADD(DATE(NOW()), INTERVAL - 5 DAY) 
    -- e.date in ('2016-11-14','2016-11-15','2016-11-16') 
    and a.lynx_country = 'BE' 

、INの後の括弧内の値は、私はさらに

SELECT 
    distinct date 
FROM 
    equity e 
WHERE 
    e.date >= DATE_ADD(DATE(NOW()), INTERVAL - 5 DAY) 

を行うだろう時に値が返されます(2つのコメント行は、2つのオプションです):

クエリは次のとおりです。結果セットは2つのクエリで同じですが、ラッパークエリを追加すると大きな違いが生じます

ラッパーを含む完全なクエリ:

select ROUND(SUM(total)/ratio, 2) as agg, date 
from (
SELECT 
    e.date, er.ratio, e.total 
FROM 
    equity e 
     JOIN 
    exchange_rate er ON e.date = er.date 
     AND LOWER(er.currency) = LOWER(e.currency) 
    join account a 
     on e.account = a.id 
WHERE 
    e.date >= DATE_ADD(DATE(NOW()), INTERVAL - 5 DAY) 
    -- e.date in ('2016-11-14','2016-11-15','2016-11-16') 
    and a.lynx_country = 'BE' 
    ) dummy 
    group by date 

間違った結果:DATE_ADD(DATE(NOW())、INTERVAL - 5 DAY)

agg   | date 
------------------------ 
68833599.13 | 2016-11-14 
69350727.47 | 2016-11-15 
69351461.28 | 2016-11-16 

正しい結果:( '2016年11月14日'、 '2016年11月15日で」、 '2016年11月16日')

agg   | date 
------------------------- 
101956327.03 | 2016-11-14 
102722297.52 | 2016-11-15 
102723384.45 | 2016-11-16 

すべてのヘルプは

+0

本当に2つのクエリ間で何が変化しているかを示すことで、質問を明確にしてください。 WHERE句は変更されていますが、2番目のクエリでは集計を行っています。 –

+0

両方のバリアントで最初のクエリの出力(集約ラッパーなし)は同じですか?そして出力は何ですか? – Kleskowy

+0

はい、出力は9000行です – ShadowFlame

答えて

0

を高く評価し、あなたはこれらを試してみていただけますか?

SELECT 
    'query a' 
, sum(case when e.date >= '2016-11-14' and < '2016-11-15' then total end) day1 
, sum(case when e.date >= '2016-11-15' and < '2016-11-16' then total end) day2 
, sum(case when e.date >= '2016-11-16' and < '2016-11-17' then total end) day3 
FROM equity e 
JOIN exchange_rate er ON e.date = er.date AND LOWER(er.currency) = LOWER(e.currency) 
JOIN account a ON e.account = a.id 
WHERE e.date >= DATE_ADD(DATE(NOW()), INTERVAL - 5 DAY) 
    and a.lynx_country = 'BE' 
; 

SELECT 
    'query b' 
, sum(case when e.date >= '2016-11-14' and < '2016-11-15' then total end) day1 
, sum(case when e.date >= '2016-11-15' and < '2016-11-16' then total end) day2 
, sum(case when e.date >= '2016-11-16' and < '2016-11-17' then total end) day3 
FROM equity e 
JOIN exchange_rate er ON e.date = er.date AND LOWER(er.currency) = LOWER(e.currency) 
JOIN account a ON e.account = a.id 
WHERE e.date in ('2016-11-14','2016-11-15','2016-11-16') 
    and a.lynx_country = 'BE' 
; 

次に試してみてください。

SELECT 
    date(e.`date`) as e_date, SUM(e.total) 
FROM equity e 
JOIN exchange_rate er ON e.date = er.date AND LOWER(er.currency) = LOWER(e.currency) 
JOIN account a ON e.account = a.id 
WHERE e.date >= DATE_ADD(DATE(NOW()), INTERVAL - 5 DAY) 
    and a.lynx_country = 'BE' 
GROUP BY 
    date(e.`date`) 

私は問題は、データが当時の時間範囲にわたって情報拡散が含まれており、INを使用しようとしているということであると信じて(...)メソッドは、あまりにも具体的ですデータを選択する

また、日付/時刻の範囲では「間」に非常に注意してください。上記の最初の2つのクエリよりも少ないイントロダクションは、3つの範囲の間に重複が全くないことを保証します。他の方法を使用すると、データに重複やギャップが生じる可能性があります。 http://sqlblog.com/blogs/aaron_bertrand/archive/2011/10/19/what-do-between-and-the-devil-have-in-common.aspx

+0

で、小さな変更(...およびe.date <...は各行に適用されます)では、両方のケースで同じ結果が得られます。 しかし、私はそれらのすべての日付を自分で計算するつもりはないので、これは実稼働環境では役に立ちません。 MySqlはそれを行うべきです.. – ShadowFlame

+0

@ShadowFlameはe.dateが 'DATE'ではなく、' DATETIME'でしたか?それが正しいとすれば、元の「動作していない」バージョンと論理的にどのように異なるのかを見ることは難しいです。私は何かを見落としていると思っていますが、それが何であるかははっきりしません。 –

+0

@ Michael-sqlbotはい、私はそれを言った。 – ShadowFlame