特定の列を除いて、テーブルのすべての列をSELECT
する方法はありますか? ITは、テーブルからすべての非ブロブ列または非ジオメトリック列を選択するのに非常に便利です。
何かのようなもの:
SELECT * -the_geom FROM segments;
このような機能はPostgresにもSQL標準(AFAIK)にもありません。これは非常に興味深い質問だと思うので、少しググって、 postgresonline.com に関する興味深い記事を見つけました。
これらは、スキーマから列を直接選択するアプローチを示しています。
SELECT 'SELECT ' || array_to_string(ARRAY(SELECT 'o' || '.' || c.column_name
FROM information_schema.columns As c
WHERE table_name = 'officepark'
AND c.column_name NOT IN('officeparkid', 'contractor')
), ',') || ' FROM officepark As o' As sqlstmt
そのようなことをする関数を作成できます。このようなトピックはメーリングリストでも議論されましたが、全体的なコンセンサスはほぼ同じでした:スキーマをクエリします。
他の解決策もあると確信していますが、それらにはすべて、ある種の魔法のスキーマ-queriying-fooが含まれると思います。
ところで、これはパフォーマンスを低下させる可能性があるため、SELECT * ...
には注意してください
本当の答えは、実際にはできないということです。これは何十年もの間要求されている機能であり、開発者はそれを実装することを拒否します。
Postgresオプティマイザは動的関数をブラックボックスと見なすため、スキーマテーブルのクエリを実行することを提案する一般的な回答は効率的に実行できません(以下のテストケースを参照)。つまり、インデックスは使用されず、結合はインテリジェントに行われません。あなたはm4のようなある種のマクロシステムがあればはるかに良いでしょう。少なくとも、オプティマイザを混乱させることはありません(ただし、混乱を招く可能性があります)。コードをフォークして機能を自分で記述したり、プログラミング言語のインターフェイスを使用したりせずに、行き詰まっています。
以下の簡単な概念実証を書いて、plpgsqlでの非常に単純な動的実行でパフォーマンスがどのように低下するかを示しました。また、以下では、汎用レコードを返す関数を特定の行タイプに強制し、列を列挙する必要があることにも注意してください。したがって、この方法は、すべてのテーブルに対してこの関数を再作成したくない限り、「すべて選択」では機能しません。
test=# create table atest (i int primary key);
CREATE TABLE
test=# insert into atest select generate_series(1,100000);
INSERT 0 100000
test=# create function get_table_column(name text) returns setof record as
$$
declare r record;
begin
for r in execute 'select * from ' || $1 loop
return next r;
end loop;
return;
end;
$$ language plpgsql;
test=# explain analyze select i from atest where i=999999;
QUERY PLAN
----------------------------------------------------------------------------------------------------
-------------------
Index Only Scan using atest_pkey on atest (cost=0.29..8.31 rows=1 width=4) (actual time=0.024..0.0
24 rows=0 loops=1)
Index Cond: (i = 999999)
Heap Fetches: 0
Planning time: 0.130 ms
Execution time: 0.067 ms
(5 rows)
test=# explain analyze
select * from get_table_column('atest') as arowtype(i int) where i = 999999;
QUERY PLAN
----------------------------------------------------------------------------------------------------
-----------------------
Function Scan on get_table_column arowtype (cost=0.25..12.75 rows=5 width=4) (actual time=92.636..
92.636 rows=0 loops=1)
Filter: (i = 999999)
Rows Removed by Filter: 100000
Planning time: 0.080 ms
Execution time: 95.460 ms
(5 rows)
直接クエリがインデックスを使用している間に関数呼び出しがテーブル全体をスキャンしたことがわかるように(95.46 ms vs. 00.07ms。)または、正しい順序でテーブルを結合します。
実際、JSONBが導入された9.4以降のPostgreSQLではある程度可能です。私は(GeoJSONを介して)Googleマップですべての利用可能な属性を表示する方法について同様の質問について考えていました。
jSONBから要素を削除することを提案するircチャネルのjohto。
ここにアイデアがあります
select the_geom,
to_jsonb(foo) - 'the_geom'::text attributes
from (
select * from
segments
) foo
個々の列の代わりにjsonを取得している間、それはまさに私が欲しかったものでした。おそらく、jsonを展開して個々の列に戻すことができます。
これを行うことができる(そうすべきではない)唯一の方法は、動的SQLステートメントを使用することです。 (DrColossosが書いたように)システムビューをクエリしてテーブルの構造を見つけ、適切なステートメントを作成するのは簡単です。
PS:テーブル構造を正確に知らないか、または記述せずに、すべてまたは一部の列を選択するのはなぜですか?
コメント で、あなたの動機は、長いコンテンツの列のcontentsを表示しないという便利さを持つことではなく、列自体を表示しないより:
…出力が文字化けする非常に長いジオメトリ文字列を表示せずに、ジオメトリック列のあるテーブルをクエリしたい場合があります。数十個あるかもしれないので、すべての列を指定したくありません。
これは、長いコンテンツをnull
(この例ではtext
列ですが、抑制したい型に合わせて変更する)に置き換えるヘルパー関数を使用して可能です。
create table my_table(foo integer, bar integer, baz text);
insert into my_table(foo,bar,baz) values (1,2,'blah blah blah blah blah blah'),(3,4,'blah blah');
select * from my_table;
foo |バー| baz -:| -:| :---------------------------- 1 | 2 |何とか何とか何とか何とか何とか何とか何とか 3 | 4 |何とか何とか
create function f(ttype anyelement) returns setof anyelement as $$ declare toid oid; tname text; nname text; cols text; begin -- select pg_type.oid, pg_namespace.nspname, pg_type.typname into toid, nname, tname from pg_type join pg_namespace on pg_namespace.oid=pg_type.typnamespace where pg_type.oid=pg_typeof(ttype); -- select string_agg((case when data_type<>'text' then column_name else 'null::'||data_type||' "'||column_name||'"' end) ,', ' order by ordinal_position) into cols from information_schema.columns where table_schema=nname and table_name=tname; -- return query execute 'select '||cols||' from '||nname||'.'||tname; -- end $$ language plpgsql;
select * from f(null::my_table);
foo |バー| baz -:| -:| :--- 1 | 2 | null 3 | 4 | null
dbfiddle ここ
大きなデータ値を含む列を表示しないことにより、デバッグ中に画面が煩雑にならないようにすることが目的の場合は、次の方法を使用できます。
(「hstore」contribパッケージをまだインストールしていない場合はインストールしてください: "CREATE EXTENSION hstore;
")
Col1、col2、col3を含むテーブル「test」の場合、表示する前に「col2」の値をnullに設定できます。
select (r).* from (select (test #= hstore('col2',null)) as r from test) s;
または、表示する前に2つの列をnullに設定します。
select (r).* from (select (test #= hstore('col2',null) #= hstore('col1',null)) as r from test) s;
注意点は、hstoreにフィードするレコードタイプを定義する必要があるため、「test」はテーブルでなければならないことです(エイリアスまたはサブセレクトは機能しません)。
私が発見した回避策はありますが、R内からSQLクエリを送信する必要があります。これは、Rユーザーに役立つ場合があります。
基本的にdplyr
パッケージはSQL(特にPostgreSQL)クエリを送信し、-(column_name)
引数を受け入れます。
だからあなたの例は次のように書くことができます:
select(segments, -(the_geom))
上記のように動的に行うことが唯一の答えですが、お勧めしません。長期的に列を追加しても、そのクエリに必ずしも必要ではない場合はどうなりますか?
必要以上の列をプルし始めます。
選択が次のように挿入の一部である場合
TableAに挿入(col1、col2、col3 .. coln)tableBから2列を除くすべてを選択します
列の一致が間違っているため、挿入は失敗します。
それは可能ですが、ほぼすべての列が必要な場合でも、書き込まれるすべての選択に対して必要なすべての列を書き込むことをお勧めします。
アプリケーションの観点からは、これは遅延ソリューションです。アプリケーションが新しい列をどうするかを自動的に知ることはほとんどありません。
データブラウザーアプリケーションは、データのメタデータをクエリして、実行中のクエリから列を除外したり、列のデータのサブセットを選択したりできます。新しいBLOBは追加時に除外できます。特定の行のBLOBデータは、必要に応じて選択できます。
動的クエリをサポートするSQLバリアントでは、テーブルのメタデータに対するクエリを使用してクエリを作成できます。あなたの意図のために、名前ではなくタイプに基づいて列を除外します。
SQL-VIEWSに_*
_が表示されない... psql
で_\d any_view
_を確認してください。内部表現には(内省的) 前処理 があります。
ここでのすべてのディスカッションは、theissueプロポーザル(質問とディスカッションに含まれる)が構文糖であることを示していますプログラマーにとっては、実際の「SQL最適化の問題」ではありません...まあ、私の推測では、それはプログラマーの80%のためです。
そのため、「事前解析イントロスペクション」として実装できます... _SELECT *
_を使用してSQL-VIEWを宣言した場合のPostgreSQLの動作を確認してください:VIEWコンストラクター変換_*
_をすべての列のリストに挿入します(イントロスペクションにより、現時点ではCREATE VIEWソースコードを実行します)。
それは実行可能な実装です。フィールド__(id serial, name text, the_geom geom)
_を含むテーブルt
があるとします。
_CREATE VIEW t_full AS SELECT * FROM t;
-- is transformed into SELECT id,name,the_geom FROM t;
CREATE VIEW t_exp_geom AS SELECT * -the_geom FROM t;
-- or other syntax as EXCEPT the_geom
-- Will be transformed into SELECT id,name FROM t;
_
PREPAREステートメント についても同様です。
...それが可能であり、それがプログラマーの80%が必要としているものです。PREPAREとVIEWSの構文砂糖です!
注:もちろん、可能な構文は、おそらく_- column_name
_ではありません。PostgreSQLに競合がある場合、_EXCEPT column_name
_を提案できます。EXCEPT (column_name1, column_name2, ..., column_nameN)
またはその他。
これは、すべての列を選択するための関数です。 postgresonline.com と postgresql tuturial のアイデアと他のソースのアイデアを組み合わせました。
CREATE TABLE phonebook(phone VARCHAR(32), firstname VARCHAR(32),
lastname VARCHAR(32), address VARCHAR(64));
INSERT INTO phonebook(phone, firstname, lastname, address)
VALUES ('+1 123 456 7890', 'John', 'Doe', 'North America'),
('+1 321 456 7890', 'Matti', 'Meikeläinen', 'Finland'),
('+1 999 456 7890', 'Maija', 'Meikeläinen', 'Finland'),
('+9 123 456 7890', 'John', 'Doe', 'Canada'),
('+1 123 456 7890', 'John', 'Doe', 'Sweden'),
('+1 123 456 7890', 'John', 'Doe2', 'North America');
drop function all_except_one(text,text);
CREATE OR REPLACE FUNCTION all_except_one(to_remove TEXT, table_name1 TEXT)
RETURNS void AS $$
DECLARE
rec_row RECORD;
curs1 refcursor ;
BEGIN
--print column names:
raise notice '%', ('|'|| ARRAY_TO_STRING(ARRAY(SELECT
COLUMN_NAME::CHAR(20) FROM INFORMATION_SCHEMA.COLUMNS WHERE
TABLE_NAME=table_name1 AND COLUMN_NAME NOT IN (to_remove) ),
'|') ||'|') ;
OPEN curs1 FOR
EXECUTE 'select table_1 from (SELECT ' || ARRAY_TO_STRING(ARRAY(
SELECT COLUMN_NAME::VARCHAR(50) FROM INFORMATION_SCHEMA.COLUMNS
WHERE TABLE_NAME=table_name1 AND COLUMN_NAME NOT IN (to_remove)
), ', ') || ' FROM ' || table_name1 || ' limit 30) table_1 ';
LOOP
-- fetch row into the rec_row
FETCH curs1 INTO rec_row;
-- exit when no more row to fetch
EXIT WHEN NOT FOUND;
-- build and print the row output
raise notice '%',(select'| '|| regexp_replace( array_to_string(
array_agg(a::char(20)),'|'),'["\(.*\)]+', '','g') ||'|' from
unnest(string_to_array(replace(replace(replace(trim(rec_row::text,
'()'),'"',''), ', ','|'),')',' '),',')) as a);
END LOOP;
-- Close the cursor
CLOSE curs1;
END; $$ LANGUAGE plpgsql;
select all_except_one('phone','phonebook');
--output:
--NOTICE: |firstname |lastname |address |
--NOTICE: | John |Doe |North America |
--NOTICE: | Matti |Meikeläinen |Finland |
--NOTICE: | Maija |Meikeläinen |Finland |
--NOTICE: | John |Doe |Canada |
--NOTICE: | John |Doe |Sweden |
--NOTICE: | John |Doe2 |North America |
-- all_except_one
-- ----------------
-- (1 row)