Postgresqlデータベースの紹介9-使用

型変換

SQLステートメントでは、意図的であろうとなかろうと、同じ式に異なるデータ型を混在させる必要があります。

PostgreSQLには、混合型式を評価するための広範な機能があります。

多くの場合、ユーザーは型変換メカニズムの詳細を理解する必要はありません。ただし、暗黙的

PostgreSQLによって行われた変換は、クエリの結果に影響を与える可能性があります。必要に応じて、これらの結果は次のように調整できます。

明示的な型変換を使用します。

この章では、PostgreSQLの型変換メカニズムと規則を紹介します。関連するセクションを参照してください

特定のデータ型と許可される関数および演算子の詳細については、第8章および第9章を参照してください。

概要(概要)

SQLは強く型付けされた言語です。つまり、すべてのデータ項目には、そのデータ型を決定するデータ型が関連付けられています

動作と許可された使用法。PostgreSQLには、他のシステムよりも一般的で柔軟性のある拡張可能な型システムがあります。

SQLの実装。したがって、PostgreSQLでのほとんどの型変換動作は、ではなく一般的なルールによって管理されます。

アドホックヒューリスティック。これにより、ユーザー定義型でも混合型式を使用できます。

PostgreSQLスキャナー/パーサーは、語彙要素を5つの基本的なカテゴリーに分類します:整数、非整数

数字、文字列、識別子、およびキーワード。ほとんどの非数値型の定数は、最初に文字列として分類されます。

SQL言語定義では、文字列を使用して型名を指定できます。このメカニズムはPostgreSQLで使用できます。

パーサーを正しいパスで開始します。たとえば、次のクエリを実行します。

SELECT text'Origin 'AS "label"、point'(0,0) 'AS "value"; 

 ラベル| 
-------- + -------
 オリジン| (0,0)
(1行)

テキスト型とポイント型の2つのリテラル定数があります。文字列リテラルにタイプが指定されていない場合、

プレースホルダータイプが不明であることが最初に割り当てられ、以下で説明するように後の段階で解決されます。

PostgreSQLパーサーには、個別の型変換ルールを必要とする4つの基本的なSQL構造があります。

関数呼び出しPostgreSQL型システムの多くは、豊富な関数セットを中心に構築されています。関数は1つ以上を持つことができます

引数。PostgreSQLは関数のオーバーロードを許可しているため、関数名だけでは一意に識別されません。

呼び出される関数。パーサーは、指定された引数のデータ型に基づいて適切な関数を選択する必要があります。

演算子PostgreSQLでは、接頭辞と接尾辞の単項(1つの引数)演算子、および2進数(2つの引数)を持つ式を使用できます。

引数)演算子。関数と同様に、演算子はオーバーロードされる可能性があるため、正しい選択の同じ問題

演算子が存在します。

値の格納SQLINSERTおよびUPDATEステートメントは、式の結果をテーブルに配置します。ステートメント内の式

ターゲット列のタイプと一致し、場合によっては変換される必要があります。

UNION、CASE、および関連する構成要素ユニオン化されたSELECTステートメントからのすべてのクエリ結果は、単一の列セットに表示される必要があるため、

各SELECT句の結果を一致させて、統一されたセットに変換する必要があります。同様に、結果式

CASE式全体が既知の出力を持つように、CASEコンストラクトのを共通の型に変換する必要があります

タイプ。ARRAY構造、およびGREATEST関数とLEAST関数についても同じことが言えます。

システムカタログには、どのデータ型の間にどの変換またはキャストが存在するか、およびその方法に関する情報が格納されます。

それらの変換を実行します。ユーザーはCREATECASTコマンドを使用してキャストを追加できます。(これは通常です

新しいデータ型の定義と併せて行われます。組み込みタイプ間のキャストのセットは慎重にされています

細工されており、変更しないことをお勧めします。)

パーサーによって提供される追加のヒューリスティックにより、適切なキャスト動作の決定を改善できます。

暗黙のキャストを持つタイプのグループ。データ型は、次のようないくつかの基本的な型カテゴリに分類されます。

ブール、数値、文字列、ビット文字列、日時、タイムスパン、幾何学、ネットワーク、およびユーザー定義。(リストについては、を参照してください

表45-49; ただし、カスタムタイプのカテゴリを作成することも可能であることに注意してください。)各カテゴリ内に1つ存在できます。

またはより好ましいタイプ。可能なタイプの選択肢がある場合に優先されます。慎重に選択して

優先タイプと使用可能な暗黙のキャストにより、あいまいな式(

複数の候補解析ソリューション)は、便利な方法で解決できます。

すべての型変換ルールは、いくつかの原則を念頭に置いて設計されています。

暗黙の変換は、驚くべきまたは予測できない結果をもたらすことはありません。

クエリが暗黙的な型変換を必要としない場合、パーサーまたはエグゼキューターに余分なオーバーヘッドがないはずです。それ

つまり、クエリが整形式であり、タイプがすでに一致している場合、クエリは余分な費用をかけずに実行する必要があります

パーサーでの時間であり、クエリに不要な暗黙の変換呼び出しを導入することはありません。

さらに、クエリが通常関数の暗黙的な変換を必要とする場合、そしてその場合、ユーザーは新しい

正しい引数タイプの関数の場合、パーサーはこの新しい関数を使用する必要があり、暗黙的ではなくなります

古い関数を使用するための変換。

操作(演算子)

演算子式によって参照される特定の演算子は、次の手順を使用して決定されます。この手順は、関係する演算子の優先順位によって間接的に影響を受けることに注意してください。これにより、どの部分式がどの演算子の入力と見なされるかが決まります。詳細については、セクション4.1.6を参照してください。

演算子タイプの解決

pg_operatorシステムカタログから検討する演算子を選択します。スキーマ修飾されていない演算子名が使用された場合(通常の場合)、考慮される演算子は、現在の検索パスに表示される名前と引数数が一致する演算子です(セクション5.7.3を参照)。修飾された演算子名が指定された場合、指定されたスキーマの演算子のみが考慮されます。

検索パスで同じ引数タイプの演算子が複数見つかった場合、パスの中で最も早く表示されている演算子のみが考慮されます。引数の種類が異なる演算子は、検索パスの位置に関係なく、同じ立場であると見なされます。

入力引数タイプを正確に受け入れる演算子を確認してください。存在する場合(考慮される演算子のセットに完全に一致するものは1つだけです)、それを使用します。

二項演算子呼び出しの1つの引数が不明なタイプである場合、それがこのチェックの他の引数と同じタイプであると想定します。2つの未知の入力を含む呼び出し、または未知の入力を持つ単項演算子は、このステップで一致するものを見つけることはありません。

最適なものを探します。

入力タイプが一致せず、(暗黙の変換を使用して)一致するように変換できない候補演算子を破棄します。未知のリテラルは、この目的のために何にでも変換可能であると見なされます。候補が1つしかない場合は、それを使用します。それ以外の場合は、次のステップに進みます。

すべての候補を実行し、入力タイプで最も完全に一致する候補を保持します。(この目的では、ドメインは基本タイプと同じと見なされます。)完全に一致するものがない場合は、すべての候補を保持します。候補が1つしかない場合は、それを使用します。それ以外の場合は、次のステップに進みます。

すべての候補を実行し、(入力データ型の型カテゴリの)優先型を受け入れる候補を、型変換が必要になるほとんどの位置に保持します。優先タイプを受け入れる候補がない場合は、すべての候補を保持します。候補が1つしかない場合は、それを使用します。それ以外の場合は、次のステップに進みます。

入力引数が不明な場合は、残りの候補者がそれらの引数の位置で受け入れるタイプカテゴリを確認してください。候補者がそのカテゴリを受け入れる場合は、各位置で文字列カテゴリを選択します。(不明なタイプのリテラルは文字列のように見えるため、この文字列へのバイアスは適切です。)それ以外の場合、残りのすべての候補が同じタイプのカテゴリを受け入れる場合は、そのカテゴリを選択します。それ以外の場合は、手がかりがないと正しい選択を推測できないため、失敗します。ここで、選択したタイプカテゴリを受け入れない候補を破棄します。さらに、いずれかの候補がそのカテゴリの優先タイプを受け入れる場合は、その引数に対して非優先タイプを受け入れる候補を破棄します。

候補が1つしかない場合は、それを使用します。候補者がいないか、複数の候補者が残っている場合は、失敗します。

いくつかの例を次に示します。

例10-1。階乗演算子タイプの解決

標準カタログで定義されている階乗演算子(後置!)は1つだけで、bigint型の引数を取ります。スキャナーは、次のクエリ式の引数に整数の初期タイプを割り当てます。

SELECT 40!AS「40階乗」; 

                   40階乗
------------------------------------------------ - 
 815915283247897734345611269596115894272000000000 
(1行)

したがって、パーサーはオペランドで型変換を行い、クエリは次と同等です。

SELECT CAST(40 AS bigint)!AS「40階乗」;

例10-2。文字列連結演算子タイプの解決

文字列のような構文は、文字列タイプの操作および複雑な拡張タイプの操作に使用されます。タイプが指定されていない文字列は、可能性のある演算子候補と照合されます。

引数が1つ指定されていない例:

SELECTテキスト 'abc' || 'def' AS "テキストと不明"; 

 テキストと不明
------------------ 
 abcdef 
(1行)

この場合、パーサーは、両方の引数のテキストを取得する演算子があるかどうかを確認します。あるので、2番目の引数はタイプテキストとして解釈されるべきであると想定しています。

不特定のタイプの連結は次のとおりです。

SELECT'abc '|| 'def' AS "unspecified"; 

 不特定
------------- 
 abcdef 
(1行)

この場合、クエリでタイプが指定されていないため、使用するタイプの最初のヒントはありません。したがって、パーサーはすべての候補演算子を検索し、文字列カテゴリとビット文字列カテゴリの両方の入力を受け入れる候補があることを検出します。使用可能な場合は文字列カテゴリが優先されるため、そのカテゴリが選択され、文字列の優先タイプであるテキストが、不明なリテラルをとして解決するための特定のタイプとして使用されます。

例10-3。絶対値と否定演算子のタイプの解決

PostgreSQL演算子カタログには、プレフィックス演算子@のエントリがいくつかあり、そのすべてがさまざまな数値データ型の絶対値演算を実装しています。これらのエントリの1つは、数値カテゴリで推奨されるタイプであるタイプfloat8用です。したがって、PostgreSQLは、不明な入力に直面したときにそのエントリを使用します。

SELECT @ '-4.5' AS "abs"; 
 abs 
----- 
 4.5 
(1行)

ここで、システムは、選択された演算子を適用する前に、未知の型のリテラルを型float8として暗黙的に解決しました。float8が使用され、他のタイプが使用されていないことを確認できます。

SELECT @ '-4.5e500' AS "abs";

エラー:「-4.5e500」は倍精度型の範囲外です。一方、プレフィックス演算子〜(ビット単位の否定)は整数データ型に対してのみ定義されており、float8に対しては定義されていません。したがって、〜で同様のケースを試してみると、次のようになります。

SELECT〜 '20' AS "否定";

エラー:演算子が一意ではありません:〜「不明」ヒント:最適な候補演算子を選択できませんでした。明示的な型キャストを追加する必要があるかもしれません。これは、システムがいくつかの可能な〜演算子のどれを優先するかを決定できないために発生します。明示的なキャストでそれを助けることができます:

SELECT〜CAST( '20' AS int8)AS "否定"; 

 否定
----------- 
      21 
(1行)

関数

関数呼び出しによって参照される特定の関数は、次の手順を使用して決定されます。

関数型の解決

pg_procシステムカタログから検討する関数を選択します。スキーマ修飾されていない関数名が使用された場合、考慮される関数は、現在の検索パスに表示される、名前と引数の数が一致する関数です(セクション5.7.3を参照)。修飾された関数名が指定された場合、指定されたスキーマ内の関数のみが考慮されます。

検索パスで同一の引数タイプの関数が複数見つかった場合、パスの中で最も早く表示されている関数のみが考慮されます。異なる引数タイプの関数は、検索パスの位置に関係なく、同じ立場で考慮されます。

関数がVARIADIC配列パラメーターで宣言されており、呼び出しでVARIADICキーワードが使用されていない場合、関数は、呼び出しに一致する必要に応じて、配列パラメーターがその要素タイプの1つ以上のオカレンスに置き換えられたかのように扱われます。このような展開の後、関数はいくつかの非可変個引数関数と同一の有効な引数タイプを持つ可能性があります。その場合、検索パスの前半にある関数が使用されます。または、2つの関数が同じスキーマにある場合は、非可変個引数関数が優先されます。

パラメータのデフォルト値を持つ関数は、デフォルト可能なパラメータ位置を0個以上省略したすべての呼び出しに一致すると見なされます。このような関数が複数呼び出しに一致する場合は、検索パスで最も早く表示される関数が使用されます。同じスキーマにデフォルト以外の位置に同一のパラメータータイプを持つそのような関数が2つ以上ある場合(デフォルト可能なパラメーターのセットが異なる場合に可能)、システムはどちらを優先するかを決定できません。呼び出しに一致するものが見つからない場合、「あいまいな関数呼び出し」エラーが発生します。

入力引数タイプを正確に受け入れる関数を確認してください。存在する場合(考慮される関数のセットに完全に一致するものは1つだけです)、それを使用します。(不明なケースは、このステップで一致するものを見つけることはありません。)

完全に一致するものが見つからない場合は、関数呼び出しが特殊な型変換要求であるように見えるかどうかを確認してください。これは、関数呼び出しに引数が1つだけあり、関数名が一部のデータ型の(内部)名前と同じである場合に発生します。さらに、関数引数は、不明な型のリテラル、名前付きデータ型にバイナリ強制可能な型、またはその型のI / O関数を適用することで名前付きデータ型に変換できる型(つまり、変換は、標準の文字列型の1つとの間で行われます)。これらの条件が満たされると、関数呼び出しはCAST仕様の形式として扱われます。[1]

最適なものを探します。

入力タイプが一致せず、(暗黙の変換を使用して)一致するように変換できない候補関数を破棄します。未知のリテラルは、この目的のために何にでも変換可能であると見なされます。候補が1つしかない場合は、それを使用します。それ以外の場合は、次のステップに進みます。

すべての候補を実行し、入力タイプで最も完全に一致する候補を保持します。(この目的では、ドメインは基本タイプと同じと見なされます。)完全に一致するものがない場合は、すべての候補を保持します。候補が1つしかない場合は、それを使用します。それ以外の場合は、次のステップに進みます。

すべての候補を実行し、(入力データ型の型カテゴリの)優先型を受け入れる候補を、型変換が必要になるほとんどの位置に保持します。優先タイプを受け入れる候補がない場合は、すべての候補を保持します。候補が1つしかない場合は、それを使用します。それ以外の場合は、次のステップに進みます。

入力引数が不明な場合は、残りの候補者がそれらの引数の位置で受け入れるタイプカテゴリを確認してください。候補者がそのカテゴリを受け入れる場合は、各位置で文字列カテゴリを選択します。(不明なタイプのリテラルは文字列のように見えるため、この文字列へのバイアスは適切です。)それ以外の場合、残りのすべての候補が同じタイプのカテゴリを受け入れる場合は、そのカテゴリを選択します。それ以外の場合は、手がかりがないと正しい選択を推測できないため、失敗します。ここで、選択したタイプカテゴリを受け入れない候補を破棄します。さらに、いずれかの候補がそのカテゴリの優先タイプを受け入れる場合は、その引数に対して非優先タイプを受け入れる候補を破棄します。

候補が1つしかない場合は、それを使用します。候補者がいないか、複数の候補者が残っている場合は、失敗します。

「ベストマッチ」ルールは、演算子と関数タイプの解決で同じであることに注意してください。いくつかの例を次に示します。

例10-4。丸め関数の引数タイプの解決

2つの引数を取るラウンド関数は1つだけです。数値型の最初の引数と整数型の2番目の引数を取ります。したがって、次のクエリは、整数型の最初の引数を数値に自動的に変換します。

SELECT round(4、4); 

 ラウンド
-------- 
 4.0000 
(1行)

そのクエリは、実際にはパーサーによって次のように変換されます。

SELECT round(CAST(4 AS数値)、4);

小数点付きの数値定数には最初に数値型が割り当てられるため、次のクエリでは型変換が不要になるため、少し効率が上がる可能性があります。

SELECTラウンド(4.0、4);

例10-5。部分文字列関数型の解決

いくつかのsubstr関数があり、そのうちの1つはtext型とinteger型を取ります。型が指定されていない文字列定数を使用して呼び出された場合、システムは、優先カテゴリ文字列(つまり、テキスト型)の引数を受け入れる候補関数を選択します。

SELECT substr( '1234'、3); 

 substr 
-------- 
     34 
(1行)

文字列がvarchar型であると宣言されている場合、テーブルからのものである場合のように、パーサーはそれをテキストに変換しようとします。

SELECT substr(varchar '1234'、3); 

 substr 
-------- 
     34 
(1行)

これは、パーサーによって次のように効果的に変換されます。

SELECT substr(CAST(varchar '1234' AS text)、3);

注:パーサーは、pg_castカタログから、textとvarcharがバイナリ互換であることを学習します。つまり、物理的な変換を行わなくても、一方を他方を受け入れる関数に渡すことができます。したがって、この場合、型変換呼び出しは実際には挿入されません。

また、整数型の引数を使用して関数が呼び出された場合、パーサーはそれをテキストに変換しようとします。

SELECT substr(1234、3);

エラー:関数substr(integer、integer)が存在しませんヒント:指定された名前と引数のタイプに一致する関数がありません。明示的な型キャストを追加する必要があるかもしれません。整数にはテキストへの暗黙のキャストがないため、これは機能しません。ただし、明示的なキャストは機能します。

SELECT substr(CAST(1234 AS text)、3); 

 substr 
-------- 
     34 
(1行)

[1]このステップの理由は、実際のキャスト関数がない場合に関数スタイルのキャスト仕様をサポートするためです。キャスト関数がある場合は、通常、出力タイプにちなんで名付けられているため、特別な場合は必要ありません。追加の解説については、CREATECASTを参照してください。

バリューストレージ

テーブルに挿入される値は、次の手順に従って宛先列のデータ型に変換されます。

値ストレージタイプ変換

ターゲットと完全に一致するかどうかを確認します。

それ以外の場合は、式をターゲットタイプに変換してみてください。2つのタイプの間に登録されたキャストがある場合、これは成功します。式が不明なタイプのリテラルである場合、リテラル文字列の内容は、ターゲットタイプの入力変換ルーチンに送られます。

ターゲットタイプのサイジングキャストがあるかどうかを確認します。サイジングキャストは、そのタイプからそれ自体へのキャストです。pg_castカタログで見つかった場合は、宛先列に格納する前に式に適用します。このようなキャストの実装関数は、常に整数型の追加パラメーターを取り、宛先列の宣言された長さを受け取ります(実際には、そのatttypmod値。atttypmodの解釈はデータ型によって異なります)。キャスト関数は、サイズチェックや切り捨てなどの長さに依存するセマンティクスを適用する役割を果たします。

例10-6。文字ストレージタイプ変換

character(20)として宣言されたターゲット列の場合、次のステートメントにより、格納された値のサイズが正しく設定されます。

CREATE TABLE vv(v character(20)); 
INSERT INTO vv SELECT'abc '|| 'def'; 
SELECT v、length(v)FROM vv; 

          v | 長さ
---------------------- + -------- 
 abcdef | 20 
(1行)

ここで実際に起こったことは、2つの未知のリテラルがデフォルトでテキストに解決され、||が許可されることです。テキスト連結として解決される演算子。次に、演算子のテキスト結果は、ターゲットの列タイプに一致するようにbpchar( "blank-padded char"、文字データ型の内部名)に変換されます。(テキストからbpcharへの変換はバイナリ強制可能であるため、この変換では実際の関数呼び出しは挿入されません。)最後に、サイジング関数bpchar(bpchar、integer)がシステムカタログで検出され、オペレーターの結果に適用され、格納されます。列の長さ。このタイプ固有の関数は、必要な長さのチェックとパディングスペースの追加を実行します。

UNION、CASE、和関連コンストラクト(UNION、CASE、および関連コンストラクト)

SQL UNION構造は、単一の結果セットになるために、おそらく異なるタイプと一致する必要があります。解決アルゴリズムは、和集合クエリの各出力列に個別に適用されます。INTERSECTおよびEXCEPT構造は、UNIONと同じ方法で異なるタイプを解決します。CASE、ARRAY、VALUES、GREATEST、およびLEASTコンストラクトは、同じアルゴリズムを使用してコンポーネント式を照合し、結果のデータ型を選択します。

UNION、CASE、および関連する構成の型解決

すべての入力が同じタイプであり、不明でない場合は、そのタイプとして解決します。それ以外の場合は、リスト内のドメインタイプを基になる基本タイプに置き換えます。

すべての入力のタイプが不明の場合は、タイプテキスト(文字列カテゴリの優先タイプ)として解決します。それ以外の場合、不明な入力は無視されます。

不明な入力がすべて同じタイプのカテゴリではない場合は、失敗します。

不明な入力タイプがあれば、そのカテゴリで優先されるタイプを最初に選択します。

それ以外の場合は、先行するすべての不明な入力を暗黙的に変換できる最後の不明な入力タイプを選択します。(少なくともリストの最初のタイプはこの条件を満たす必要があるため、常にそのようなタイプがあります。)

すべての入力を選択したタイプに変換します。特定の入力から選択したタイプへの変換がない場合は失敗します。

いくつかの例を次に示します。

例10-7。ユニオン内のタイプが指定されていないタイプの解決

SELECTテキスト 'a' AS "テキスト" UNION SELECT'b '; 

 テキスト
------ 
 a 
 b 
(2行)

ここでは、不明なタイプのリテラル「b」がテキストタイプに解決されます。

例10-8。単純なユニオンでのタイプ解決

SELECT 1.2AS「数値」UNIONSELECT 1; 

 数値
--------- 
       1 
     1.2 
(2行)

リテラル1.2は数値型であり、整数値1を暗黙的に数値にキャストできるため、型が使用されます。

例10-9。転置されたユニオンのタイプ解決

SELECT 1 AS "real" UNION SELECT CAST( '2.2' AS REAL); 

 実数
------ 
    1 
  2.2 
(2行)

ここで、実数型を暗黙的に整数にキャストすることはできませんが、整数を暗黙的に実数にキャストできるため、和集合の結果型は実数として解決されます。

おすすめ

転載: blog.csdn.net/qq_37061368/article/details/112984876