グループ化するアイテムを選択していないためです。あなたが言った場合:
GROUP BY c.printable_name
期待されるNULLを取得します。ただし、別の列でグループ化しているため、MySQLはprintable_nameがロールアップグループに参加していることを認識せず、 all の結合で、その列から古い値を選択します。 登録。 (したがって、ウズベキスタン以外の国が表示される可能性があります。)
これは、MySQLがGROUPBYクエリでSELECTできるものを許容するというより広範な問題の一部です。たとえば、次のように言うことができます:
SELECT gender FROM registrations GROUP BY country;
また、MySQLは、国と性別の間に直接的な因果関係(別名「関数従属性」)がない場合でも、各国から登録するために性別の値の1つを喜んで選択します。他のDBMSは、国ごとに1つの性別が保証されていないという理由で、上記のコマンドを拒否します。(*)
さて、これ:
SELECT c.printable_name AS 'Country', count(*) AS '#'
FROM registrations r
INNER JOIN country c ON r.country = c.country_id
GROUP BY country
r.countryとc.printable_nameの間に機能的な依存関係があるため、問題ありません(country_idを主キーとして正しく記述していると仮定します)。
ただし、MySQLのWITH ROLLUP拡張機能は、動作方法が少しハックされています。最後のロールアップ行ステージでは、事前グループ化の結果セット全体を実行して値を取得し、次に group-by列をNULLに設定します。 その列に機能的に依存している他の列もnullになりません。 おそらくそうすべきですが、MySQLは現在、機能依存性についてすべてを実際に理解しているわけではありません。
したがって、c.printable_nameを選択すると、ランダムに選択した国名の値が表示され、c.country_idを選択すると、ランダムに選択した国IDが表示されます— c.country_idが参加基準である場合でも、 NULLであるr.countryと同じです!
問題を回避するためにできることは次のとおりです。
- 代わりにprintable_nameでグループ化します。 printable_namesが一意である場合、または
- 「r.country」とprintable_nameを選択し、NULLであることを確認するか、
- WITH ROLLUPを忘れて、最終合計に対して別のクエリを実行します。これは少し遅くなりますが、ANSI SQL-92に準拠しているため、アプリは他のデータベースで動作します。
(*:MySQLにはSQL_MODEオプションがあります ONLY_FULL_GROUP_BY これはこの問題に対処することになっていますが、行き過ぎであり、GROUP BYに機能的に依存している列ではなく、GROUPBYから列を選択することしかできません。そのため、有効なクエリも失敗し、通常は役に立たなくなります。)