MySQLをスキーマレスDBとして扱うための試行錯誤のログ2

前回の記事で、やりたいことを実現することはできましたが、indexが効かないので全然実用的ではありませんでした。
そこで別の方法を模索してみます。

MySQLはユーザー変数を使った独自の集計(GROPU BY)を行うことでがきます。
ただし、MySQLのクエリー実行の順番を理解していないと作れません。超難解ですがとても複雑なGROUP BYでも結構実装できてしまいます。

SQLをFROM → WHERE → SELECT → GROUP → HAVING といった順番にループするプログラムと考えて、ユーザー変数をそれぞれの箇所で適切に制御することで、アクロバティックで、プログラミングのような処理が可能になります。

尚、WHERE句で(ユーザー変数)*0+1としているのは、ユーザー変数の初期化を行うためだけのもので、WHEREの条件を常に1(真)とする為です。ちなみにcなどのif文中と同じで、AND条件は前から順番に処理され、条件に合致しなくなったらexitするので、ユーザー変数の初期化や制御はWHERE句の前の方に置く必要があります。またindexが使われた場合は、index以外の行は読み込まれません。(ユーザー変数によるカウントは不可、そうでなければユーザー変数で非表示行もカウントが可能です。)

  • ユーザー変数を使った独自 GROUP BY
SELECT @num,@cond,@type,@category,@repeat,v.* 
  FROM (SELECT @num:=0,@user_id:=0,@cond:=0,@type:=0,@repeat:=0,@category:='') setup,(
SELECT 1 n,1455 user_id,1 type,4 value  UNION ALL 
SELECT 2  ,1455        ,2     ,'apple'  UNION ALL 
SELECT 3  ,784         ,1     ,8        UNION ALL 
SELECT 4  ,784         ,2     ,'orange' UNION ALL 
SELECT 5  ,784         ,3     ,5        UNION ALL 
SELECT 6  ,784         ,4     ,'option' UNION ALL 
SELECT 7  ,3151        ,1     ,6        UNION ALL 
SELECT 8  ,3151        ,2     ,'apple'  UNION ALL 
SELECT 9  ,3151        ,3     ,7
) v 
WHERE (@num:=@num+1)*0+1 
  AND (@type:=type)*0+1 
  AND (@repeat:=  IF(type=1,value,@repeat  ))*0+1
  AND (@category:=IF(type=2,value,@category))*0+1
  AND (@cond:=IF(@type=1,0,@cond))*0+1  
  AND (@cond:=IF((type=1 AND value > 3) 
              OR (type=2 AND value='apple'),@cond:=@cond+1,@cond))*0+1
  AND IF(@cond=2,(@cond:=0)+1,0) 
  AND ((type=1 AND value > 3) OR (type=2 AND value='apple'))

ところで、MySQLのviewにはユーザー変数や、サブクエリーは使えません...。ダメじゃん。