ORDER BY句は、PostgreSQLのドキュメントで次のように説明されています。
ORDER BY expression [ ASC | DESC | USING operator ] [ NULLS { FIRST | LAST } ] [, ...]
誰かがUSING operator
の使用例を教えてもらえますか?結果セットの交互の順序を取得することは可能ですか?
非常に簡単な例は次のとおりです。
_> 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
などのプリミティブ型には主に_<
_および_>
_関数があり、配列やベクトルなどにはさらにいくつかあることに気づくでしょう。これらの演算子は、カスタムの注文を取得するのに役立ちません。
カスタム順序付けが必要なmostの場合、... ORDER BY somefunc(tablecolumn) ...
のようなものを使用して回避できます。ここで、somefunc
は値を適切にマップします。これはすべてのデータベースで機能するため、これも最も一般的な方法です。単純なものについては、カスタム関数の代わりに式を書くこともできます。
ギアの切り替え
_ORDER BY ... USING
_はいくつかの場合に意味があります:
somefunc
トリックは機能しません。point
、circle
、または虚数など)を使用していて、奇妙な計算でクエリを繰り返したくない場合。ここでは、複雑なデータ型に焦点を当てます。多くの場合、合理的な方法でそれらを並べ替える方法は複数あります。良い例はpoint
です:(0,0)までの距離、または最初にx、次にyの順に並べるか、またはyまたはその他の必要なものだけ。
もちろん、PostgreSQL haspoint
の定義済み演算子:
_ > CREATE TABLE p ( p point );
> SELECT p <-> point(0,0) FROM p;
_
しかしnoneそれらのうち、デフォルトで_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
_には、定義されたセマンティクスの演算子が必要です。明らかに、これは2項演算子でなければならず、引数と同じ型を受け入れ、ブール値を返す必要があります。また、推移的である必要があると思います(a <bおよびb <cの場合、a <c)。さらに要件がある場合があります。しかし、これらすべての要件は、適切なbtree-index順序付けにも必要です。これは、btreeへの参照を含む奇妙なエラーメッセージについて説明しています。
_ORDER BY USING
_を定義するには、演算子1つだけでなく演算子クラスと演算子ファミリも必要です。 1つのcouldは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の内部で興味深い外観です。しかし、データベーステクノロジーの特定の領域veryで作業しない限り、すぐに必要になるものはありません。
別の例は Postgres docs。 にあり、例のソースコードは here および here です。この例では、演算子の作成方法も示しています。
サンプル:
CREATE TABLE test
(
id serial NOT NULL,
"number" integer,
CONSTRAINT test_pkey PRIMARY KEY (id)
)
insert into test("number") values (1),(2),(3),(0),(-1);
select * from test order by number USING > //gives 3=>2=>1=>0=>-1
select * from test order by number USING < //gives -1=>0=>1=>2=>3
したがって、desc
およびasc
と同等です。しかし、あなたはあなた自身の演算子を使うかもしれません、それはUSING
の本質的な機能です
いい答えですが、「USING」の本当に価値あるケースについては言及されていません。
デフォルト以外の演算子ファミリを使用してインデックスを作成した場合、たとえば、varchar_pattern_ops
の代わりに~>~
(~<~
、~>=~
、<
、...) >
、>=
インデックスに基づいて検索し、order by句でインデックスを使用する場合は、適切な演算子でUSING
を指定する必要があります。
これは、次の例で説明できます。
CREATE INDEX index_words_Word ON words(Word text_pattern_ops);
この2つのクエリを比較してみましょう。
SELECT * FROM words WHERE Word LIKE 'o%' LIMIT 10;
そして
SELECT * FROM words WHERE Word LIKE 'o%' ORDER BY Word LIMIT 10;
50万語のDBでは、実行の違いはほぼ100倍です。また、C以外のロケールでは結果が正しくない場合があります。
これはどうして起こりましたか?
LIKE
およびORDER BY
句を使用して検索を行う場合、実際には次の呼び出しを行います。
SELECT * FROM words WHERE Word ~>=~ 'o' AND Word ~<~'p' ORDER BY Word USING < LIMIT 10;
インデックスは~<~
演算子を考慮して作成されているため、PGは特定のORDER BY
句で特定のインデックスを使用できません。正しい処理を行うには、クエリを次の形式に書き直す必要があります。
SELECT * FROM words WHERE Word ~>=~ 'o' AND Word ~<~'p' ORDER BY Word USING ~<~ LIMIT 10;
または
SELECT * FROM words WHERE Word LIKE 'o%' ORDER BY Word USING ~<~ LIMIT 10;
オプションで、ORDER BY句の任意の式の後に、Word ASC(昇順)またはDESC(降順)というキーを追加できます。指定しない場合、デフォルトでASCが想定されます。または、特定の順序付け演算子名をUSING句で指定できます。順序付け演算子は、一部のBツリー演算子ファミリーの「以下」または「以上」のメンバーである必要があります。 ASCは通常USING <と同等であり、DESCは通常USING>と同等です。
このように見えるかもしれません(現在、これを確認するためのpostgresはありませんが、後で確認します)。
SELECT Name FROM Person
ORDER BY NameId USING >