2017-03-07 31 views
0

私は、ユーザーが書いたテイスティングノートと、他のユーザーが各試飲ノートに与える評価を保持する別のテーブルを持っています。mySQLの結果を戻すべきではありません

あなたはまだこのようなルックスを評価していない他のユーザによって書かれているすべての音符れますクエリ:

SELECT tastingNotes.userID, tastingNotes.beerID, tastingNotes.noteID, tastingNotes.note, COALESCE(sum(tasteNoteRate.Score), 0) as count, 
CASE 
WHEN tasteNoteRate.userVoting = 1162 THEN 1 
ELSE 0 
END AS userScored 
FROM tastingNotes 
left join tasteNoteRate on tastingNotes.noteID = tasteNoteRate.noteID 
WHERE tastingNotes.userID != 1162 
Group BY tastingNotes.noteID 
HAVING userScored < 1 
ORDER BY count, userScored 

ユーザ1162がそれが示しtasteNoteRateテーブルにはノート113用のノートを書いていますがアップ:それはまだ....上記のクエリが実行されるたびに返され

noteID | userVoting | score 
    113  1162  0 

しかし、内側に

+2

SQL92に準拠した 'GROUP BY'を読んでください – Kermit

+0

正確に何を探すべきか@Kermit – Mike

+0

私は、あなたが達成しようとしていることとこの試みを説明するのにも役立つかもしれないと思いますそれはあなたが期待したように動作していません。この特定のアプローチは完全に間違っているかもしれませんし、あなたがしようとしていることをやるためのより簡単な方法があるかもしれません。 – moreON

答えて

0

変更が加わります。

tasteNoteRateテーブルがtastingNotesに結合されたままになっています。つまり、tastingNotesテーブル全体が返され、tasteNoteRateテーブルの一致するフィールドによって展開されます。 tasteNoteRateが満たされない場合、tastingNotesが一致したフィールドを返すのを防ぐことはできません。内部結合が交差点を取ります。

は、加入のタイプのより詳細な説明についてはこちらをご覧ください:

What's the difference between INNER JOIN, LEFT JOIN, RIGHT JOIN and FULL JOIN?

はすぐに爆発する場合を両方のテーブルのノートIDのインデックスまたはこのクエリを作成して使用することを確認します。

注:ユースケースとして書いたことに基づいて、私はまだnoteIDに参加したいと確信していません。それは、すべてのユーザーのすべての評価で結合されたすべてのメモの結合されたテーブルを提供しようとします。私はCASE ... ENDはクエリオプティマイザを妨害し、それをフルスキャン+ジョインに変えようとしていると思います。なぜ、別の句をwhereに追加しないのですか... "and tasteNoteRate.userVoting = 1162"?

これらのテーブルが1-1ではない場合(sum()とgroup byを指定した場合)、現在のクエリに爆発的な問題が発生します。すべての音符が10の異なる定格を持ち、10の音符がある場合、100の候補結果行があります。 1000と1000になると、メモリが不足します。 userIDが投票していない行を削除すると、最終的に1,000,000以上の行が10行分削除され、合計とグループ化されますか?

あなたがそれを行うことができ、他の方法は、左を逆にすることです参加:

select ...,sum()... from tasteNoteRate ... left join tastingNotes using (noteID) where userID != xxx group by noteID、あなたが唯一の他のユーザーのノート用tastingNotes情報を取得し、そのように。

多分役立つかもしれませんが、SCHEMAと具体的な使用例/サンプルデータが役に立ちます。

このような「評価の格付け」では、投票集計のサマリーテーブルを維持し、ユーザーが既に投票したものだけを追跡する方がよい場合があります。例えば選択クエリでそれらを合計しないでください。代わりに、insert...on duplicate key update (total = total + 1)にまとめてください。少なくとも、いくつかのユーザーランキングテーブルでこの問題をどのように処理するかについてです。彼らはちょうどとてもすごく大きく成長します。

2

MySQLはあなたがdocumentationを参照してください、文句なしにかなり特別な方法でgroup byを使用することができます:

ONLY_FULL_GROUP_BYが無効になっている場合は、GROUP BYの標準SQLを使用することにMySQLの拡張は、HAVING、選択リストを許可します条件、またはORDER BYリストを使用して、列が機能的にGROUP BY列に依存していない場合でも、非集約列を参照できます。 [...] この場合、サーバーは各グループから任意の値を自由に選択できるので、同じ値でないと選択した値は不確定です。これはおそらくとは異なります。

この動作は、MySQL 5.7より前のデフォルト動作でした。そこに複数の行が特定のnoteIDためtasteNoteRateであるので、他の誰がすでに集約関数なしtasteNoteRate.userVotingを使用しているノート、userScored、に投票した場合、ベースとなる場合には、意味あなたの場合は

ランダムな行 - おそらく間違った行。

あなたが集計使用していることを修正することができます:

:( null以外に)比較の結果は、1または0のいずれかであるため、

select ..., 
    max(CASE 
    WHEN tasteNoteRate.userVoting = 1162 THEN 1 
    ELSE 0 
    END) AS userScored 
from ... 

か、を、あなたも短いバージョンを使用することができます

select ..., 
    coalesce(max(tasteNoteRate.userVoting = 1162),0) AS userScored 
from ... 

のMySQL 5.7へのアップグレードの準備(とONLY_FULL_GROUP_BYを有効)であることを、あなたはあなたのselect -listでもすでにgroup byすべての非集計列べき:group by tastingNotes.userID, tastingNotes.beerID, tastingNotes.noteID, tastingNotes.note。これも

select tastingNotes.*, 
     coalesce(rates.count, 0) as count, 
     coalesce(rates.userScored,0) as userScored 
from tastingNotes 
left join (
    select tasteNoteRate.noteID, 
     sum(tasteNoteRate.Score) as count, 
     max(tasteNoteRate.userVoting = 1162) as userScored 
    from tasteNoteRate 
    group by tasteNoteRate.noteID 
) rates 
on tastingNotes.noteID = rates.noteID and rates.userScored = 0 
where tastingNotes.userID != 1162 
order by count; 

:あなたはgroup bytastingNotesのすべての列を持っていないので、

(とりわけ)クエリを書くの別の方法は、サブクエリでtastingNoteRatesのグループ化を行うことであろうonの文節のrates.userScored = 0= 1に変更する(または削除する)ことで、ユーザーが投票したメモを取得することができます。

+0

大きな説明! – Mike

関連する問題