web-dev-qa-db-ja.com

MySQLの大文字小文字を区別するVarcharの結合

2つのテーブルがあり、どちらも同じデータ型、文字セット、および照合順序が明示的に指定されています。

CLERK CHAR(3) CHARACTER SET latin1 COLLATE latin1_bin NULL

CLERKフィールドでの大文字と小文字を区別する結合の場合、結合句でも照合を指定する必要がありますか、それともDDLレベルで指定されているという事実は、参加?

FROM
    CUSTOMER S JOIN 
    CLERK C ON S.CLERK = C.CLERK COLLATE latin1_bin
1
GWR

CLERKフィールドでの大文字と小文字を区別する結合の場合、結合句でも照合を指定する必要がありますか、それともDDLレベルで指定されているということは、参加?

簡単な答え:クエリで照合を指定する必要はありません。DDLレベルの照合(特に、両側が同じで、両側が列の場合)は、使用されます(そのため、最初にDDLレベルで指定します)。


詳細な回答:特定の操作(連結、述語など)で使用する照合の優先順位の階層があります。使用される照合順序は、列であるかリテラルであるかだけでなく、Unicodeであるか非Unicodeであるか、さらにはバイナリであるか非バイナリであるかによっても異なります。完全な説明は、ここにあります 式の照合の強制性 。これは、そのバージョンを使用しているため、MySQL 5.7のドキュメントです。興味深いルールは次のとおりです。

同じ文字セットのオペランドを使用するが、_bin照合と_ciまたは_cs照合が混在する演算では、_bin照合が使用されます。これは、非バイナリ文字列とバイナリ文字列を混在させる操作が、オペランドをバイナリ文字列として評価する方法と似ていますが、データ型ではなく照合順序である点が異なります。

以上のことをすべて述べた上で、「バイナリ照合は大文字と小文字を区別する」というステートメントは指摘しなければなりませんが、極端によくあることは間違いです。

  1. 非常に基本的なレベルでは、並べ替えは異なります。大文字と小文字を区別する照合は、「a」を「A」でソートします(どちらが先に来るかはカルチャに依存します)、「b」は「B」でソートされます。バイナリ照合順序は、各文字の基になる値/コードポイントに従って並べ替えられます。これは、大文字と小文字のバージョンの文字が、値に従って他の文字で区切られている場合に非常に明確になります。

  2. 大文字と小文字を区別するということは、アクセントの他の文字の他のプロパティに対しても「区別しない」ことができることを意味します。これは、非Unicode文字セットに関しては他の唯一のプロパティでもありますが、Unicodeではかなの型の感度、幅の感度、およびSQL Server(バージョン2017現在)では、バリエーションセレクターの感度も可能です。バイナリ照合では、他の形式の文字が存在していても、文字が自分以外のものと同じになることはありません。繰り返しになりますが、これは非Unicode文字セットではそれほど発生しませんが、Unicodeでは、ワイド、上付き、下付き、イタリック、上下逆(「ターン」と呼ばれる)など、いくつかのバージョンの文字が存在する可能性があります。 。MySQLは、バージョン8.0以降(私の知る限り)で、感度オプションにバリエーションを追加しています(少なくともut8mb4文字セットと照合順序の場合)。

これらの両方の点を説明するために、素晴らしい db <> fiddle のデモを設定しました。 _ai_ci照合を取得するだけでなく、COLLATE latin1_general_ci句(2番目から最後のクエリ、#5)が影響を与えなかったため、MySQL 8.0を使用する必要がありました(奇妙な理由により、照合名に_ciのみが含まれている場合、_aidb <> fiddle上のMySQL 5.6と5.7の両方の場合でも、動作は_as_csまたは_binのままです)。

さらに、バイナリ照合が「大文字と小文字を区別しない」他の方法もあります。次のことは説明できません。

  • 分音記号を組み合わせる
  • 拡張
  • 収縮

これらは8ビットエンコーディングに関係していないため、これらの例を挙げたり提供したりはしていません。また、latin1は8ビットエンコーディングです。これらはUnicodeの機能なので、すべきはすべてのUnicode照合に適用されます(MySQLではテストしていませんが、SQL Serverで正しく実装されています)。

追伸このすべて(上記のUnicode固有の動作を含む)の詳細な説明は、次の投稿にあります: いいえ、バイナリ照合は大文字と小文字を区別しません 。現在はSQL Serverのコンテキストでのみフレーム化されていますが、時間があるときにこの答えを思いついた例で作業できます。重要なことは、RDBMS間で概念が同じであることです。


参考のために(念のためdb <> fiddleにアクセスできない場合)、クエリは次のとおりです。

クエリ1

CREATE TABLE CLERK (
  CLERK_ID INT NOT NULL AUTO_INCREMENT PRIMARY KEY,
  CLERK CHAR(3) CHARACTER SET latin1 COLLATE latin1_bin NULL
);

CREATE TABLE CUSTOMER (
  CUSTOMER_ID INT NOT NULL AUTO_INCREMENT PRIMARY KEY,
  NAME VARCHAR(10) NOT NULL,
  CLERK CHAR(3) CHARACTER SET latin1 COLLATE latin1_bin NULL,
  CLERK_CI_AI CHAR(3) CHARACTER SET latin1 COLLATE latin1_general_ci NULL
);

INSERT INTO CUSTOMER (NAME, CLERK, CLERK_CI_AI) VALUES('John Doe', 'Ü', 'Ü');

INSERT INTO CLERK (CLERK) VALUES('Ü');
INSERT INTO CLERK (CLERK) VALUES('ü');
INSERT INTO CLERK (CLERK) VALUES('U');
INSERT INTO CLERK (CLERK) VALUES('u');
INSERT INTO CLERK (CLERK) VALUES('Ù');
INSERT INTO CLERK (CLERK) VALUES('ù');
INSERT INTO CLERK (CLERK) VALUES('Û');
INSERT INTO CLERK (CLERK) VALUES('û');

INSERT INTO CLERK (CLERK) VALUES('Y');
INSERT INTO CLERK (CLERK) VALUES('y');
INSERT INTO CLERK (CLERK) VALUES('Ý');
INSERT INTO CLERK (CLERK) VALUES('ý');

クエリ2

SELECT 0 AS "ver", C.*
FROM   CLERK C;

クエリ3

SELECT "bin sort" AS "ver", C.*
FROM   CLERK C
ORDER BY C.CLERK;

クエリ4

SELECT "cs sort" AS "ver", C.*
FROM   CLERK C
ORDER BY C.CLERK COLLATE latin1_general_cs;

クエリ5

SELECT 1 AS "ver", S.*, C.*
FROM CUSTOMER S
JOIN CLERK C
  ON S.CLERK = C.CLERK;

クエリ6

SELECT 2 AS "ver", S.*, C.*
FROM CUSTOMER S
JOIN CLERK C
  ON S.CLERK = C.CLERK COLLATE latin1_bin;

クエリ7

SELECT 3 AS "ver", S.*, C.*
FROM CUSTOMER S
JOIN CLERK C
  ON S.CLERK_CI_AI = C.CLERK;

クエリ8

SELECT 4 AS "ver", S.*, C.*
FROM CUSTOMER S
JOIN CLERK C
  ON S.CLERK_CI_AI = C.CLERK COLLATE latin1_bin;

クエリ9

# is accent-sensitive even though documentation states it should be
# accent-INsensitive
# 
SELECT 5 AS "ver", S.*, C.*
FROM CUSTOMER S
JOIN CLERK C
  ON S.CLERK_CI_AI = C.CLERK COLLATE latin1_general_ci;

クエリ10

SELECT 6 AS "ver", S.*, C.*
FROM CUSTOMER S
JOIN CLERK C
  ON CONVERT(S.CLERK_CI_AI using utf8mb4)
       = CONVERT(C.CLERK USING utf8mb4) COLLATE utf8mb4_0900_ai_ci;
2
Solomon Rutzky