web-dev-qa-db-ja.com

SELECT * n番目の列を除く

SELECT *を実行できますが、n-th列はありません(例:2nd)?

4列と5列のビューがいくつかあります(2番目の列を除いてそれぞれ異なる列名があります)が、2番目の列を表示したくありません。

SELECT * -- how to prevent 2nd column to be selected?
FROM view4
WHERE col2 = 'foo';

SELECT * -- how to prevent 2nd column to be selected?
FROM view5
WHERE col2 = 'foo';

すべての列をリストする必要はありません(すべての列の列名が異なるため)。

8
Kokizzu

本当の答えは、実際にはできないということです( [〜#〜] link [〜#〜] を参照)。これは何十年にもわたって要求されてきた機能であり、開発者はそれを実装することを拒否しています。ベストプラクティスは、*の代わりに列名を指定することです。ただし、*自体を使用すると、パフォーマンスが低下します。

ただし、本当に使用する必要がある場合は、スキーマから直接列を選択する必要がある場合があります->チェック [〜#〜] link [〜#〜] 。または、2つのPostgreSQL組み込み関数を使用した以下の例のように:[〜#〜] array [〜#〜]およびARRAY_TO_STRING 。 1つ目はクエリ結果を配列に変換し、2つ目は配列コンポーネントを文字列に連結します。リストコンポーネントセパレータは、ARRAY_TO_STRING関数の2番目のパラメータで指定できます。

SELECT 'SELECT ' ||
ARRAY_TO_STRING(ARRAY(SELECT COLUMN_NAME::VARCHAR(50)
    FROM INFORMATION_SCHEMA.COLUMNS
    WHERE TABLE_NAME='view4' AND
            COLUMN_NAME NOT IN ('col2')
    ORDER BY ORDINAL_POSITION
), ', ') || ' FROM view4';

ここで、文字列は標準演算子||で連結されます。 COLUMN_NAMEデータ型はinformation_schema.sql_identifierです。このデータ型では、CHAR/VARCHARデータ型に明示的に変換する必要があります。

しかし、それもお勧めできません。長期的には列を追加しても、そのクエリに必ずしも必要ではない場合はどうでしょうか。必要以上の列を引き出し始めます。

選択が次のように挿入の一部である場合はどうなりますか

Insert into tableA (col1, col2, col3.. coln) Select everything but 2 columns FROM tableB

列の一致が間違っており、挿入が失敗します。

可能ですが、ほぼすべての列が必要な場合でも、書き込まれるすべての選択に対して必要なすべての列を書き込むことをお勧めします。

結論:

すでにVIEWを使用しているため、最も簡単で信頼性の高い方法は、2番目の列を除いて、列名の表示と言及を変更することです。

11
Nadeem_MK
-- my table with 2 rows and 4 columns 
DROP TABLE IF EXISTS t_target_table;
CREATE TEMP TABLE t_target_table as 
SELECT 1 as id, 1 as v1 ,2 as v2,3 as v3,4 as v4
UNION ALL 
SELECT 2 as id, 5 as v1 ,-6 as v2,7 as v3,8 as v4
;

-- my computation and stuff that i have to messure, any logic could be done here !
DROP TABLE IF EXISTS t_processing;
CREATE TEMP TABLE t_processing as 
SELECT *, md5(t_target_table::text) as row_hash, case when v2 < 0 THEN true else false end as has_negative_value_in_v2
FROM t_target_table
;

-- now we want to insert that stuff into the t_target_table 

-- this is standard
-- INSERT INTO t_target_table (id, v1, v2, v3, v4) SELECT id, v1, v2, v3, v4 FROM t_processing;

-- this is andvanced ;-) 

INSERT INTO t_target_table 
-- the following row select only the columns that are pressent in the target table, and ignore the others.
SELECT r.* FROM (SELECT to_jsonb(t_processing) as d FROM t_processing) t JOIN LATERAL jsonb_populate_record(NULL::t_target_table, d) as r ON TRUE
;
-- WARNING : you need a object that represent the target structure, an exclusion of a single column is not possible