GROUP BY句でSELECT句のすべての非集計フィールドを繰り返すことをSQLが強制するのはなぜですか? [閉まっている]

StackOverflow https://stackoverflow.com/questions/416625

  •  03-07-2019
  •  | 
  •  

質問

これは長い間私を悩ませてきました。

99%の場合、GROUP BY句は、SELECT句の正確なコピーから、集約関数(MAX、SUMなど)を除いたものです。
これは、自分自身を繰り返さないという原則を破ります。

GROUP BY句に、SELECT句から集約関数を除いた正確なコピーを含めないのはいつですか?

編集

一部の実装では、SELECTよりもGROUP BYに異なるフィールドを使用できることを認識しています(したがって、100%ではなく99%)が、確かにそれは非常に小さな例外ですか?
別のフィールドを使用した場合に返される内容を誰かが説明できますか?

ありがとう。

役に立ちましたか?

解決

私はあなたに同意する傾向があります-これは、すべての入力を節約するために、SQLがわずかにスマートなデフォルトを持つべきである多くのケースの1つです。たとえば、これが合法かどうかを想像してください:

Select ClientName, InvoiceAmount, Sum(PaymentAmount) Group By *

where" *" 「すべての非集計フィールド」を意味します。誰もがそれがどのように機能するかを知っていれば、混乱はありません。トリッキーなことをしたい場合は、フィールドの特定のリストに潜ることができますが、感嘆符は「すべて」を意味します。 (このコンテキストでは、すべての可能なものを意味します)。

許可済み、「*」ここでは、SELECT句とは異なるものを意味するため、異なる文字を使用した方が適切な場合があります。

Select ClientName, InvoiceAmount, Sum(PaymentAmount) Group By !

SQLほど雄弁ではないような領域が他にもいくつかあります。しかし、現時点では、そのような多くの大きな変更を行うにはおそらくあまりにも定着しているでしょう。

他のヒント

これらは2つの異なるものであるため、select句にないアイテムでグループ化できます

編集:

また、その仮定をするのは安全ですか?

SQLステートメントがあります

Select ClientName, InvAmt, Sum(PayAmt) as PayTot

それは「正しい」ですか?サーバーがClientName AND InvoiceAmountでグループ化することを前提としていますか? 私は個人的にこのコードを使用することを好みます(そしてより安全だと思います)

Select ClientName, InvAmt, Sum(PayAmt) as PayTot
Group By ClientName

エラーをスローして、コードを変更するように促します

Select ClientName, Sum(InvAmt) as InvTot, Sum(PayAmt) as PayTot
Group By ClientName

まもなく包括的なものが見つかることを期待/期待します。このテーマに関するSQLの歴史のレッスンは有益で有益です。誰でも?誰でも? Bueller?

その間、次のことを確認できます。

SQLは、少なくとも Pragmatic Programmerに文書化されている限り、DRYの原則よりも前のことです。

すべてのDBが完全なリストを必要とするわけではありません。たとえば、Sybaseは次のようなクエリを喜んで実行します

SELECT a, b, COUNT(*)
FROM some_table
GROUP BY a

...(少なくとも私がそのようなモンスターを誤って実行するたびに)しばしば非常に大きな不注意なレコードセットにつながり、パニックに襲われたリクエストがすぐに発生し、DBAにサーバーをバウンスさせるように頼みます。結果は一種の部分的なデカルト積ですが、ほとんどの場合、SybaseがSQL標準を適切に実装できなかったためだと思います。

おそらく、短縮形が必要です-GroupSelectと呼びます

GroupSelect Field1, Field2, sum(Field3) From SomeTable Where (X = "3")

この方法では、集計関数を省略した場合にパーサーがエラーをスローするだけです。

これの正当な理由は、すべての列を指定しなかった場合よりも、誤った結果が頻繁に得られることです。 3つの列、 col1 col2 、および col3 があるとします。

データが次のようになっているとします:

Col1  Col2 Col3
a      b    1
a      c    1
b      b    2
a      b    3

col1、col2でmytableグループからcol1、col2、sum(col3)を選択します
次の結果が得られます。

Col1  Col2 Col3
a      b    4
a      c    1
b      b    2

どのように解釈するか
col1によってmytableグループからcol1、col2、sum(col3)を選択します

私の推測は

Col1  Col2 Col3
a      b    5
a      c    5
b      b    2

これらは明らかに悪い結果です。もちろん、クエリが複雑で結合が多いほど、クエリが正しい結果を返す可能性は低くなり、プログラマーはそれらが間違っているかどうかさえ知るようになります。

個人的に、 group by にフィールドが必要であることを嬉しく思います。

GROUP BY ALL、GROUP BY *、または同様のものに同意します。元の投稿で述べたように、99%(おそらくそれ以上)のケースで、すべての非集約列/式でグループ化したい。

ただし、下位互換性の理由から、GROUP BY列が必要になる場合の1つの例があります。

SELECT 
  MIN(COUNT(*)) min_same_combination_cnt, 
  MAX(COUNT(*)) max_same_comb_cnt, 
  AVG(COUNT(*)) avg_same_comb_cnt, 
  SUM(COUNT(*)) total_records,
  COUNT(COUNT(*)) distinct_combinations_cnt
FROM <some table>
GROUP BY <list of columns>

これはOracleで機能します。列の選択性を推定するために使用します。 group byは、内部集計関数に適用されます。次に、外側の集約が適用されます。

SQL標準に対するこの改善のための提案を提出することは素晴らしいことです。どのように機能するかわかりません。

実際には、それは100%の時間ではないでしょうか? GROUP BYにないselectの(非集約)列を持つことができる場合はありますか?

私は答えがありません。それは確かに言語にとって厄介な瞬間のように思えます。

私は、特に非集計フィールドにifや関数などの精巧なステートメントが含まれている場合、繰り返しは少し面倒であるという見解を共有しています。 group by句に何らかの速記があればいいのですが、少なくとも列エイリアスです。列を番号で参照することは、おそらく独自の問題があるとはいえ、別のオプションかもしれません。

たとえば、グループ化されたすべての行の1つのIDとその合計を抽出する必要がある場合があります。この場合、名前でグループ化し、グループ化されていないIDのままにします。 SQLiteはこのように動作するようです。

グループごとの結果は、タプルのグループ全体に対して単一のタプルであるため、他の非グループごとの属性は、集計関数でのみ使用する必要があります。 selectで非グループ属性を追加すると、sqlはそのグループから選択する値を決定できません。

ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top