非常に簡単な例は次のとおりです。
> SELECT * FROM tab ORDER BY col USING <
しかし、これは退屈です。これは、従来のORDER BY col ASC
では得られないものだからです。 。
また、標準カタログには、奇妙な比較関数/演算子についてエキサイティングなことは何も記載されていません。それらのリストを取得できます:
> SELECT amoplefttype::regtype, amoprighttype::regtype, amopopr::regoper
FROM pg_am JOIN pg_amop ON pg_am.oid = pg_amop.amopmethod
WHERE amname = 'btree' AND amopstrategy IN (1,5);
ほとんどの場合、<
があることに気付くでしょう。 および>
integer
のようなプリミティブ型の関数 、date
など、配列やベクトルなどの場合はさらにいくつか。これらの演算子はいずれも、カスタム注文を取得するのに役立ちません。
ほとんど カスタムオーダーが必要な場合は、... ORDER BY somefunc(tablecolumn) ...
のようなものを使用して回避できます。 ここで、somefunc
値を適切にマップします。これはすべてのデータベースで機能するため、これも最も一般的な方法です。簡単なことについては、カスタム関数の代わりに式を書くこともできます。
ギアを切り替える
ORDER BY ... USING
いくつかの場合に意味があります:
- 順序は非常に珍しいため、
somefunc
トリックは機能しません。 - 非プリミティブ型(
point
など)を使用している 、circle
または虚数)、奇妙な計算でクエリを繰り返したくない場合。 - 並べ替えるデータセットが非常に大きいため、インデックスによるサポートが必要であるか、必要でさえあります。
複雑なデータ型に焦点を当てます。多くの場合、合理的な方法でそれらを並べ替える方法は複数あります。良い例はpoint
です :(0,0)までの距離、または xで「並べ替え」ることができます 最初に、次に y またはy または他に必要なもの。
もちろん、PostgreSQLは point
の事前定義された演算子 :
> CREATE TABLE p ( p point );
> SELECT p <-> point(0,0) FROM p;
しかし、なし そのうちのORDER BY
で使用可能と宣言されています デフォルト(上記を参照):
> SELECT * FROM p ORDER BY p;
ERROR: could not identify an ordering operator for type point
TIP: Use an explicit ordering operator or modify the query.
point
の単純な演算子 「下」と「上」の演算子です<^
および>^
。単純にy
を比較します ポイントの一部。しかし:
> SELECT * FROM p ORDER BY p USING >^;
ERROR: operator > is not a valid ordering operator
TIP: Ordering operators must be "<" or ">" members of __btree__ operator families.
ORDER BY USING
セマンティクスが定義された演算子が必要です。明らかに、二項演算子である必要があり、引数と同じ型を受け入れ、ブール値を返す必要があります。また、推移的である必要があると思います(a btreeにも必要です。 -インデックスの順序。これは、 btreeへの参照を含む奇妙なエラーメッセージを説明しています 。
ORDER BY USING
また、1人のオペレーターだけでなく、 定義する必要がありますが、演算子クラス およびオペレーターファミリー 。 1つはできた 1つの演算子のみで並べ替えを実装すると、PostgreSQLは効率的に並べ替えを行い、比較を最小限に抑えようとします。したがって、1つだけを指定した場合でも、いくつかの演算子が使用されます。他の演算子は特定の数学的制約に準拠する必要があります。推移性についてはすでに説明しましたが、他にもあります。
ギアを切り替える
適切なものを定義しましょう:y
のみを比較するポイントの演算子 一部。
最初のステップは、 btreeで使用できるカスタム演算子ファミリーを作成することです。 インデックスアクセス方式。参照
> CREATE OPERATOR FAMILY xyzfam USING btree; -- superuser access required!
CREATE OPERATOR FAMILY
次に、2点を比較するときに-1、0、+1を返すコンパレータ関数を提供する必要があります。この関数は 内部で呼び出されます!
> CREATE FUNCTION xyz_v_cmp(p1 point, p2 point) RETURNS int
AS $$BEGIN RETURN btfloat8cmp(p1[1],p2[1]); END $$ LANGUAGE plpgsql;
CREATE FUNCTION
次に、ファミリの演算子クラスを定義します。番号の説明については、マニュアルを参照してください。
> CREATE OPERATOR CLASS xyz_ops FOR TYPE point USING btree FAMILY xyzfam AS
OPERATOR 1 <^ ,
OPERATOR 3 ?- ,
OPERATOR 5 >^ ,
FUNCTION 1 xyz_v_cmp(point, point) ;
CREATE OPERATOR CLASS
このステップでは、いくつかの演算子と関数を組み合わせ、それらの関係と意味も定義します。例:OPERATOR 1
意味:これはless-than
の演算子です テスト。
ここで、演算子<^
および>^
ORDER BY USING
で使用できます :
> INSERT INTO p SELECT point(floor(random()*100), floor(random()*100)) FROM generate_series(1, 5);
INSERT 0 5
> SELECT * FROM p ORDER BY p USING >^;
p
---------
(17,8)
(74,57)
(59,65)
(0,87)
(58,91)
出来上がり-yでソート 。
要約すると: ORDER BY ... USING
PostgreSQLの内部で興味深い外観です。ただし、非常にで作業しない限り、すぐに必要なものは何もありません。 データベーステクノロジーの特定の分野。
別の例は、Postgresのドキュメントにあります。こことここの例のソースコードを使用します。この例は、演算子を作成する方法も示しています。