2016-11-11 18 views
0

私はのMySQL、InnoDBのSQL_CALC_FOUND_ROWSを使用してUNION ALLといくつかの問題を抱えている動作していません。まず、私は何が起こっているのかを説明するために単純なデータベースのスキーマを表示してみましょう...のMySQL、UNION ALLはSQL_CALC_FOUND_ROWSと時々

Database Schema

メディア表

media_id title 
------------------------------------- 
1   Empire of the Sun 

ジャンルのパターン表

genre_id name 
------------------------------------- 
1   Action 
2   Adventure 

ロケール表

locale_id code 
------------------------------------- 
1   en_US 
2   pt_BR 
3   fr_FR 

ジャンル翻訳表

genre_id locale translation 
------------------------------------- 
1   1   Action 
1   2   Ação 
2   1   Adventure 
2   2   Aventura 

メディアジャンルの表

media_id genre_id 
------------------------------------- 
1   1 
1   2 

は、今では簡単です:私はユーザーロケールと互換性のあるジャンル名を返す必要があります。ユーザーロケールがpt_BRであるとします。私はフォローのSQLを使用した結果を得るために:

name 
------------------------------------- 
Ação 
Aventura 
をしかし、それでは、ユーザーロケールがfr_FRのであると仮定してみましょう:

select gt.name 
from media_genres mg 
inner join genre_translation gt on (mg.genre_id = gt.genre_id) 
where (mg.media_id = 1 and gt.locale_id = 2) 

それを返します。 fr_FRの翻訳はありません。

select SQL_CALC_FOUND_ROWS gt.name 
from media_genres mg 
inner join genre_translation gt on (mg.genre_id = gt.genre_id) 
where (mg.media_id = 1 and gt.locale_id = 3) 

UNION ALL 

select gt.name 
from media_genres mg 
inner join genre_translation gt on (mg.genre_id = gt.genre_id) 
where FOUND_ROWS() = 0 and (mg.media_id = 1 and gt.locale_id = 1) 

locale_id = 3とmedia_idこの= 1には見つかった行はありませんならば、私は= locale_idの結果を得ることができます:私が見つけた解決策は、私は、次のSQLを使用し、ALL SQL_CALC_FOUND_ROWSとUNIONを使用しました1(デフォルト)とmedia_id = 1

問題は次のとおりです。この文は正しいデータを返すことがあり、時にはデータを返しません。

私の主な質問:これはなぜ起こっていますか?

+0

最初の 'SELECT'が最初に実行されるという保証はないので、最初の行から2番目の' SELECT'が 'FOUND_ROWS()'に依存することはできません1。 – Barmar

+0

2つのサブクエリが同じ数のカラムを返さないため、エラーが発生するはずです。 2番目のサブクエリは本当に最初のものと同じように 'mg.genre_id、gt.name'を返しますか? – Barmar

+0

フィードバックありがとうございます!私は間違って "mg.genre_id"というフィールドを書いていましたが、SQLのこのフィールドがなくても...私は同じ結果を持っています:時々データが返されることもあります... – itscaiqueck

答えて

0

これを達成する方法は、LEFT JOINを使用して変換テーブルに結合し、IFNULLを使用して一致がない場合にデフォルトを指定します。

SELECT mg.genre_id, IFNULL(gt2.name, gt1.name) AS name 
FROM media_genres AS mg 
JOIN genre_translation AS gt1 ON mg.genre_id = gt.genre_id AND gt.locale_id = 1 
LEFT JOIN genre_translation AS gt2 ON mg.genre_id = gt.genre_id AND gt.locale_id = 3 
WHERE mg.media_id = 1 
+0

これはうまくいきました。 「gt1」に変更します。 「gt2」と表示されます。 joinステートメントで!どうもありがとうございます。このクエリのパフォーマンスは良好ですか? – itscaiqueck

+0

あなたは 'genre_translation.genre_id'にインデックスを持っている限り良いはずです。 – Barmar