なぜBYの後の表に、元GROUP列を直接参照することはできません

列の後の制限BY SELECT GROUP

  SQL標準の規定、表集計クエリのみSELECT句でコンテンツの以下の3種類を書き込むことができる場合:GROUPを重合キーで指定された句、集合関数(SUM、AVGなど)、定数によって。私たちは例を見て

  私たちは、生徒のクラステーブル(tbl_student_class)を持っており、以下のようにデータは以下のとおりです。

DROP  TABLE  IFは EXISTS tbl_student_classを。
CREATE  TABLEのtbl_student_classを(
  IDのINT8)符号なしNOT  NULL AUTO_INCREMENTコメント' 自增主键' 
  SNOのVARCHAR12NOT  NULL COMMENT ' 学号' 
  CNO VARCHAR5NOT  NULL COMMENT ' 班级号] 
  CNAME VARCHAR20NOT  NULL COMMENT ' クラス名' PRIMARY  KEY (ID)
)COMMENT = ' 学生のクラスのテーブル' ; 

- ------------------------- --- 
- tbl_student_classの記録
- ---------------------------- 
INSERT  INTO tbl_student_class VALUES' 1 '' 20190607001 '' 0607 '' 膜7は、クラス' );
 INSERT  INTOtbl_student_class VALUES' 2 '' 20190607002 '' 0607 '' 膜7クラス' );
 INSERT  INTO tbl_student_class VALUES' 3 '' 20190608003 '' 0608 '' ビデオクラス8 ' );
 INSERT  INTO tbl_student_class ' 4 ''20190608004' ' 0608 ' ' ビデオクラス8 ' );
 INSERT  INTO tbl_student_class VALUES' 5 ' ' 20190609005 ' ' 0609 ' ' 膜9クラス' );
 INSERT  INTO tbl_student_class VALUES' 6 ' ' 20190609006 '' 0609 '' 映画9クラス');

  私たちは、それぞれのクラス(クラス番号、クラス名)の人々の数をカウントしたい、と私たちは、クエリSQLを書くことができますどのように最大の学生数を、持っていますか?私たちはできるようにすべきだと思います

SELECT CNO、CNAME、カウント、(SNO)MAX (SNO) 
 FROM tbl_student_classの
 GROUP  BY CNO、CNAME。

  しかし、一部の人々はCNOは一度、CNAMEもSQLを書くことそうではないと判断し、CNOとcnameは常に一つとなって、思うだろうか?

SELECT CNOは、CNAMEは、カウント(SNO)、MAX (SNO) 
 FROM tbl_student_classの
 GROUP  BY CNO。

  実行エラー:

のErr ]  1055  -式#2   SELECTリストがある しない  GROUP  BYおよび 含有非凝集カラム test.tbl_student_class.cname  はない機能的依存 GROUP  BY節を、これは、ある非互換 sql_modeの= ONLY_FULL_GROUP_BY

  プロンプト:それは重合の関数ではない間に、第2の式(CNAME)のSELECTリストは、GROUP BY句ではない; SQLこのモード:ONLY_FULL_GROUP_BY互換性がありません。

  なぜ直接に(ないGROUP BY句に)GROUP BYの後に元の表を参照することができないカラム 門司は、私たちはゆっくりと見て。

SQLモード

  MySQLサーバは、SQLの異なるモードで動作することができ、システム変数のsql_modeの値に応じて、異なるクライアントに対してこれらのモードでの異なる方法で適用することができます。SQL DBAグローバルパターンは、サイトサーバーの動作要件に適合するように設けられてもよいし、各アプリケーションは、独自の会話モードのSQL要求を提供することができます。モードは、実行するMySQLのサポートSQL構文とデータの検証チェックに影響を与え、異なる環境でのMySQLを使用し、他のデータベースサーバと一緒にMySQLを使用するようにすることが容易になります。:詳細については、公式ウェブサイトを参照してくださいSQLモード審査の注目は、MySQLの独自のバージョンと一致しているときのMySQLの異なるバージョンは、コンテンツは、(デフォルト値を含む)若干異なります。

  構文チェックとデータ型のサポートクラス、次のように一般的に使用される:SQLモードは、主に2つのカテゴリに分類されます

  構文サポートクラス    

    ONLY_FULL_GROUP_BY

      集計GROUP BY操作のために、SELECTの列は、HAVING句または列BY ORDERは、GROUP BYに表示されない場合、SQLは正当でない場合

    ANSI_QUOTES

      それは、識別子、 'と同じ効果と解釈されるので、ANSI_QUOTESは、その後、ストリング二重引用符を参照するために使用することができない、有効。それを設定した後、tは= F1設定更新「」...は、そのようなフィールドリストの構文エラーで不明な列「」を報告します

    PIPES_AS_CONCAT

    NO_TABLE_OPTIONS

      エンジン等、クロスのmysqldump DB移行のこの種を使用するときには考慮される必要がある、SHOWはCREATE TABLEを使用する場合のMySQL固有の構文は、出力の一部ではありません

    NO_AUTO_CREATE_USER

      文字通り、自動的にユーザーを作成しません。MySQLのユーザー認証は、我々はGRANTを使用することに慣れている場合は... ON ...一緒にユーザーを作成する機会を取るDBUSERします。操作は、Oracleに類似した後、このオプションを設定するには、最初の承認前にユーザーを作成する必要があります

  データの種類を確認します   

    NO_ZERO_DATE

      「0000-00-00」違法日付を考慮して、バックstrictモードについて設定されています

      1.厳密モードが設定されている場合、NO_ZERO_DATE自然が出会います。しかし、INSERTあれば無視するかUPDATEは、「0000-00-00」を無視し、それでも警告のみ表示することができます。

      2、非厳密モデル、上記と同様の効果を、提供NO_ZERO_DATE、「0000-00-00」であれば、警告表示ができない。NO_ZERO_DATEに設定されていない場合、警告、完全に有効な値として、

      図3に示すように、正規2010-01-00か否か、すなわち、0であってもよいか否かの日付と曜日を制御することを除いて、上記と同様NO_ZERO_IN_DATEケース。

    NO_ENGINE_SUBSTITUTION

      ALTER TABLEを使用して、またはTABLE指定ENGINEを作成すると、必要なストレージエンジンは無効になっているか、どのように対処するために、コンパイルされません。NO_ENGINE_SUBSTITUTIONを有効にすると、エラーがスロー指示し、この値はデフォルトのストレージエンジンの代替でCREATE、設定されていない場合、ATLERは、変更を行い、警告をスローしません。

    STRICT_TRANS_TABLES

      strictモードを有効に示すために設定されています。注だけではなく、いくつかの戦略の組み合わせをSTRICT_TRANS_TABLES UPDATEまたは無効な値がどのように対処するより少なく表​​示され、挿入するには、参照します。

      図1は、0を有効にした場合、前述の「パスINT、不正厳密モードでは、警告を生成する、非厳密なモデルとなります。

      図2に示すように、範囲外、最大境界値内に挿入されます。

      それは値DEFAULT句非NULLカラム、カラムの値が欠落していない明示的な定義が含まれていないときに、新しい行が挿入される3、。

  デフォルトモード

    我々は、設定ファイルを変更する必要はありません場合は、MySQLは、独自のデフォルトのモードを持って、異なるバージョン、デフォルトのモードは異なっています

- ビューMySQLバージョン
SELECT VERSION(); 

- ViewがSQL_MODE 
SELECT  @@のsql_modeのを

     私たちは、デフォルトモード5.7.21が含まれていることを見ることができます:

ONLY_FULL_GROUP_BY、STRICT_TRANS_TABLES、NO_ZERO_IN_DATE、NO_ZERO_DATE、ERROR_FOR_DIVISION_BY_ZERO、NO_AUTO_CREATE_USER、NO_ENGINE_SUBSTITUTION

    最初:ONLY_FULL_GROUP_BYは、制約されます:私たちはクエリを凝集すると、SELECT列は直接句カラムで非GROUPを含めることはできません我々は(「strictモード」を「リラックスモード」から)モードを取り除く場合はどうしますか?

    私たちは、SQLの上記のエラーことがわかりました

-- 宽松模式下 可以执行
SELECT cno,cname,count(sno),MAX(sno) 
FROM tbl_student_class
GROUP BY cno;
View Code

    能正常执行了,但是一般情况下不推荐这样配置,线上环境往往是“严格模式”,而不是“宽松模式”;虽然案例中,无论是“严格模式”,还是“宽松模式”,结果都是对的,那是因为 cno 与 cname 唯一对应的,如果 cno 与 cname 不是唯一对应,那么在“宽松模式下” cname 的值是随机的,这就会造成难以排查的问题,有兴趣的可以去试试。那为什么会有 ONLY_FULL_GROUP_BY 模式呢 我们继续往下看

  阶(order)是用来区分集合或谓词的阶数的概念。谓词逻辑中,根据输入值的阶数对谓词进行分类。= 或者 BETWEEEN 等输入值为一行的谓词叫作"一阶谓词",而像 EXISTS 这样输入值为行的集合的谓词叫作"二阶谓词"(HAVING 的输入值也是集合,但它不是谓词)。以此类推,三阶谓词=输入值为"集合的集合"的谓词,四阶谓词=输入值为"集合的集合的集合"的谓词,但是 SQL 里并不会出现三阶
以上的情况,所以不用太在意。简单点如下图

  谈到了阶,就不得不谈下集合论;集合论是 SQL 语言的根基,因为它的这个特性,SQL 也被称为面向集合语言。只有从集合的角度来思考,才能明白 SQL 的强大威力。通过上图,相信大家也都能看到,这里不做更深入的讲解了,有兴趣的可以去查相关资料。

为什么聚合后不能再引用原表中的列

  很多人都知道聚合查询的限制,但是很少有人能正确地理解为什么会有这样的约束。表 tbl_student_class 中的 cname 存储的是每位学生的班级信息,但需要注意的是,这里的 cname 只是每个学生的属性,并不是小组的属性,而 GROUP BY 又是聚合操作,操作的对象就是由多个学生组成的小组,因此,小组的属性只能是平均或者总和等统计性质的属性,如下图

  询问每个学生的 cname 是可以的,但是询问由多个学生组成的小组的 cname 就没有意义了。对于小组来说,只有"一共多少学生"或者"最大学号是多少?"这样的问法才是有意义的。强行将适用于个体的属性套用于团体之上,纯粹是一种分类错误;而 GROUP BY 的作用是将一个个元素划分成若干个子集,使用 GROUP BY 聚合之后,SQL 的操作对象便由 0 阶的"行"变为了 1 阶的"行的集合",此时,行的属性便不能使用了。SQL 的世界其实是层级分明的等级社会,将低阶概念的属性用在高阶概念上会导致秩序的混乱,这是不允许的。此时我相信大家都明白:为什么聚合后不能再引用原表中的列 。

单元素集合也是集合

  现在的集合论认为单元素集合是一种正常的集合。单元素集合和空集一样,主要是为了保持理论的完整性而定义的。因此对于以集合论为基础的 SQL 来说,当然也需要严格地区分元素和单元素集合。因此,元素 a 和集合 {a} 之间存在着非常醒目的层级差别。

a ≠ {a}

  这两个层级的区别分别对应着 SQL 中的 WHERE 子句和 HAVING 子句的区别。WHERE 子句用于处理"行"这种 0 阶的对象,而 HAVING 子句用来处理"集合"这种 1 阶的对象。

总结

  1、SQL 严格区分层级,包括谓词逻辑中的层级(EXISTS),也包括集合论中的层级(GROUP BY);

  2、有了层级区分,那么适用于个体上的属性就不适用于团体了,这也就是为什么聚合查询的 SELECT 子句中不能直接引用原表中的列的原因;

  3、一般来说,单元素集合的属性和其唯一元素的属性是一样的。这种只包含一个元素的集合让人觉得似乎没有必要特意地当成集合来看待,但是为了保持理论的完整性,我们还是要严格区分元素和单元素集合;

参考

  《SQL基础教程》

  《SQL进阶教程》

おすすめ

転載: www.linuxidc.com/Linux/2019-09/160762.htm