2017-06-09 4 views
2

を数えるので、私は次の構造を持っている:私は回数をカウントしたいとbが200非連続的に水平に行きました(と300をちょうど今のところ200)は非連続的な値に

+------+---------------+---------------+----+ 
| guid | current_level | current_value | pk | 
+------+---------------+---------------+----+ 
| a |   100 |   12 | 1 | 
| a |   200 |   12 | 2 | 
| a |   200 |   12 | 3 | 
| a |   200 |   12 | 4 | 
| a |   200 |   12 | 6 | 
| a |   300 |   14 | 7 | 
| a |   300 |   12 | 9 | 
| a |   300 |   12 | 10 | 
| a |   300 |   14 | 12 | 
| b |   100 |   10 | 5 | 
| b |   100 |   10 | 8 | 
| b |   200 |   12 | 11 | 
| b |   200 |   12 | 13 | 
+------+---------------+---------------+----+ 

を つまり、その結果、私は期待してい:

+------+-------+-------+ 
| guid | level | times | 
+------+-------+-------+ 
| a | 200 |  1 | 
| b | 200 |  1 | 
+------+-------+-------+ 

(200Sの別の筋は別々にカウントされなければならないので、私はちょうどユニークで行うことはできません)

私は次の操作を実行する場合:

set @id = "none"; 
set @lev = 10; -- arbitary non zero starting level 

SELECT guid, current_level , if(@id <> guid, @lev := 10, 0) AS useless, case when @id <> guid then @id := guid else 0 end AS useless2 
     , (case when (current_level = 200 AND current_level <> @lev) then 1 else 0 end) as TIMES 
     , if(current_level = 200 AND current_level <> @lev, @lev := current_level, 0) AS useless3 

FROM (SELECT * FROM sensor_logs order by guid) as T 

私が手:

set @id = "none"; 
set @lev = 10; -- arbitary non zero starting level 

SELECT guid, current_level , if(@id <> guid, @lev := 10, 0) AS useless, case when @id <> guid then @id := guid else 0 end AS useless2 
     , sum(case when (current_level = 200 AND current_level <> @lev) then 1 else 0 end) as TIMES 
     , if(current_level = 200 AND current_level <> @lev, @lev := current_level, 0) AS useless3 

FROM (SELECT * FROM sensor_logs order by guid) as T 
GROUP BY guid 

しかし、私は、次の取得:すなわち、だから今​​によって TIMES列とグループ化を合計すると、トリックを行う必要があります

+------+---------------+---------+----------+----------+----------+ 
| guid | current_level | useless | useless2 | TIMES | useless3 | 
+------+---------------+---------+----------+----------+----------+ 
| a |   100 |  10 | a  |  0 |  0 | 
| a |   200 |  0 | 0  |  1 |  200 | 
| a |   200 |  0 | 0  |  0 |  0 | 
| a |   200 |  0 | 0  |  0 |  0 | 
| a |   200 |  0 | 0  |  0 |  0 | 
| a |   300 |  0 | 0  |  0 |  0 | 
| a |   300 |  0 | 0  |  0 |  0 | 
| a |   300 |  0 | 0  |  0 |  0 | 
| a |   300 |  0 | 0  |  0 |  0 | 
| b |   100 |  10 | b  |  0 |  0 | 
| b |   100 |  0 | 0  |  0 |  0 | 
| b |   200 |  0 | 0  |  1 |  200 | 
| b |   200 |  0 | 0  |  0 |  0 | 
+------+---------------+---------+----------+----------+----------+ 

+------+---------------+---------+----------+----------+----------+ 
| guid | current_level | useless | useless2 | TIMES | useless3 | 
+------+---------------+---------+----------+----------+----------+ 
| a |   100 |  10 | a  |  4 |  0 | 
| b |   100 |  10 | b  |  2 |  0 | 
+------+---------------+---------+----------+----------+----------+ 

Iなぜ2つの1(各guidに1つ)がある列を合計すると4と2になるのか分かりません。

私は間違っていますか?クエリ(およびサム関数)がどのように実行されるかについての根本的な仕組みとは何か?

+0

あなたが200 –

答えて

1

あなたの最初のクエリ方が良い、このようにそれを書く:

SELECT guid, current_level , if(@id <> guid, @lev := 10, 0) AS useless, case when @id <> guid then @id := guid else 0 end AS useless2 
     , (case when (current_level = 200 AND current_level <> @lev) then 1 else 0 end) as TIMES 
     , if(current_level = 200 AND current_level <> @lev, @lev := current_level, 0) AS useless3 

FROM sensor_logs 
, (SELECT @id := 'none', @lev := 10) var_init_subquery 
ORDER BY guid 

をだけでなく、必要なときに、それはよりクリーンなもにつながる可能性があるサブクエリでそれをやって、ないサブクエリでは、明示的順序付けを行うことです悪い実行計画(一時表の場合はパフォーマンスが悪いことを意味します)。

最終結果として、GROUP BYなどを直接適用しないでください。 SELECT(したがって変数と計算)はのGROUP BYの後にと評価されます。あなたの計算の後にグループ化を行うには、サブクエリでクエリを置く:

SELECT guid, SUM(times) FROM (
    SELECT guid, current_level , if(@id <> guid, @lev := 10, 0) AS useless, case when @id <> guid then @id := guid else 0 end AS useless2 
      , (case when (current_level = 200 AND current_level <> @lev) then 1 else 0 end) as TIMES 
      , if(current_level = 200 AND current_level <> @lev, @lev := current_level, 0) AS useless3 

    FROM sensor_logs 
    , (SELECT @id := 'none', @lev := 10) var_init_subquery 
    ORDER BY guid 
) sq 
GROUP BY guid 
+0

はありがとうのocurrencesを加算していることは明らかです!完璧に動作します。パフォーマンスの観点から、これはどこにあるのでしょうか? (中規模のデータベースの場合) – user3690467

+0

あなたのマシンに完全に依存します。フィルタリングは行われないので、フルテーブルスキャンを行います。 – fancyPants

+0

問題を考えると、これについては「スマート」な方法がありますか? – user3690467

関連する問題