SQL : 일부를 제외한 모든 열 선택


108

SELECT특정 열을 제외하고 테이블의 모든 열에 대한 방법이 있습니까? IT 부서는 테이블에서 비 블롭 또는 비 기하 열을 모두 선택하는 데 매우 편리합니다.

다음과 같은 것 :

SELECT * -the_geom FROM segments;
  • 테이블에 열을 추가하면 쿼리 결과가 변경 되므로이 기능이 SQL 표준 에서 의도적으로 제외되었다고 들었습니다 . 이것이 사실입니까? 인수가 유효합니까?
  • 특히 PostgreSQL에서 해결 방법이 있습니까?

일부를 제외한 모든 열을 알고 싶은 유스 케이스는 무엇입니까? 수동 쿼리를 수행하는 동안 화면에 표시되는 것입니까? 프로그램의 일부입니까?
joanolo

2
6 의미 짧은 컬럼 (a 라 갖는 테이블 name, age, sid긴 이진 alongwith 화면 폭에 잘 맞는) geom칼럼. 기하학 바이너리를 제외한 모든 필드를 쿼리하고 이름을 하나씩 작성하는 것은 지루합니다.
Adam Matan

이 경우 이것은 SQL 자체보다 대화식 쿼리에 사용하는 도구와 관련이있을 수 있습니다.
joanolo

1
@joanolo 일반 PostgreSQL 쉘.
Adam Matan

3
이것은 너무 명백해 보인다. 흥미롭지 않거나 결과 테이블이 화면에 맞도록 (특히 명령 행 클라이언트가 사용되는 경우) 하나 또는 두 개의 열을 인쇄하지 않으려는 경우가 있습니다. 나는 구문이 같은 기대select (!coluns2,!column5) from sometable;
gumkins

답변:


54

이러한 기능은 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와 관련이 있다고 생각합니다.

BTW : SELECT * ...성능이 저하 될 수 있으므로 주의하십시오


그러한 기능을 만드는 방법? 알 수없는 쿼리를 반환하는 함수를 만드는 방법을 찾을 수 없으므로 항상 테이블을 미리 선언해야합니다.
ePascoal

17

진짜 대답은 당신이 실제로 할 수 없다는 것입니다. 이것은 수십 년 동안 요청 된 기능이었으며 개발자는이 기능을 구현하기를 거부했습니다.

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.46ms vs. 00.07ms ) 이러한 종류의 함수는 인덱스를 사용하거나 테이블을 조인하는 데 필요한 복잡한 쿼리를 올바르게 처리합니다. .


1
재미있는 관점. 이것은 분명히 코드가 아닌 인간 사용자를위한 기능이므로 클라이언트가 책임을 져야한다는 점을 알 수 있습니다. 아마도 확장 디스플레이 (\ x on)와 같은 것은 클라이언트에서 순전히 구현되며 생략 열도 비슷한 위치에 구현해야합니다.
Max Murphy

13

JSONB가 도입 된 9.4부터 PostgreSQL에서 실제로 가능합니다. Google지도에 GeoJSON을 통해 사용 가능한 모든 속성을 표시하는 방법에 대한 비슷한 질문에 대해 숙고하고있었습니다.

irc 채널의 johto는 JSONB에서 요소를 삭제하려고 제안했습니다.

여기 아이디어가 있습니다

select the_geom,
  row_to_json(foo)::jsonb - 'the_geom'::text attributes
from (
  select * from
  segments
) foo

개별 열 대신 json을 얻는 동안 정확히 내가 원하는 것입니다. 아마도 json은 개별 열로 다시 확장 될 수 있습니다.


네, 아마도 여기에서 뭔가가 있지만 아직 작동하지 않습니다.
questions

6

그렇게 할 수있는 유일한 방법은 동적 SQL 문을 사용하는 것입니다. DrColossos가 작성한 것처럼 시스템 뷰를 쿼리하고 테이블의 구조를 찾고 적절한 명령문을 작성하는 것은 쉽습니다.

추신 : 왜 정확히 테이블 구조를 알지 못하고 쓰지 않고 모든 / 일부 열을 선택하고 싶습니까?


7
PS와 관련하여 : 때로는 출력을 왜곡하는 매우 긴 기하학 문자열을 표시하지 않고 기하학적 열이있는 테이블을 쿼리하려고합니다. 수십 개가있을 수 있기 때문에 모든 열을 지정하고 싶지 않습니다.
Adam Matan

따라서 동적 SQL 만 입력하면 많은 시간을 절약 할 수 있습니다 :-).
Marian

모두 쿼리를하는 사람이 데이터베이스를 디자인 한 사람이라고 가정합니다. :-) 엑셀을 생성하기 위해 많은 필드 (30 개 이상)가있는 오래된 데이터베이스를 쿼리해야하지만 민감한 정보를 제공하지 않는 하나 또는 두 개의 필드가 있다고 가정합니다.
유서

3

위에서 언급 한 것처럼 동적으로 대답하는 것이 좋지만 권장하지는 않습니다. 장기적으로 더 많은 열을 추가하지만 해당 쿼리에 반드시 필요한 것은 아닌 경우

필요한 것보다 더 많은 열을 당기기 시작합니다.

선택이 다음과 같이 삽입물의 일부인 경우

tableA에 삽입 (col1, col2, col3 .. coln) tableB에서 2 열을 제외한 모든 항목을 선택하십시오.

열 일치가 잘못되어 삽입이 실패합니다.

가능하지만 거의 모든 열이 필요한 경우에도 모든 선택 항목에 필요한 모든 열을 작성하는 것이 좋습니다.


이 접근법은 분명히 프로그래밍 방식으로 잘못되었지만 SELECTs에 대한 콘솔 쿼리로 무해하고 유용합니다 .
Adam Matan

3

큰 데이터 값을 가진 열을 표시하지 않고 디버깅하는 동안 화면에서 혼란을 제거하는 것이 목표라면 다음과 같은 트릭을 사용할 수 있습니다.

( "hstore"contrib 패키지가 없으면 설치하십시오 : " CREATE EXTENSION hstore;")

col1, col2, col3이있는 테이블 "test"의 경우, 표시하기 전에 "col2"값을 null로 설정할 수 있습니다.

select (r).* from (select (test #= hstore('col2',null)) as r from test) s;

또는 표시하기 전에 두 개의 열을 null로 설정하십시오.

select (r).* from (select (test #= hstore('col2',null) #= hstore('col1',null)) as r from test) s;

주의해야 할 점은 hstore에 공급되는 레코드 유형을 정의해야하므로 "test"는 테이블 (별명 또는 부속 선택이 작동하지 않음)이어야한다는 것입니다.


3

방금 발견 한 해결 방법이 있지만 R 내에서 SQL 쿼리를 보내야합니다. R 사용자에게 유용 할 수 있습니다.

기본적으로 dplyr패키지는 SQL (특히 PostgreSQL) 쿼리를 보내고 -(column_name)인수를 받습니다 .

따라서 다음과 같이 예제를 작성할 수 있습니다.

select(segments, -(the_geom))

3

에서 코멘트 당신은 당신의 동기가 아니라 표시의 편의를 갖도록 설명 내용이 긴 콘텐츠로 열을보다는 열 자체를 표시하지 :

… 때때로 출력을 왜곡시키는 매우 긴 지오메트리 문자열을 표시하지 않고 기하 열이있는 테이블을 쿼리하려고합니다. 수십 개가있을 수 있기 때문에 모든 열을 지정하고 싶지 않습니다.

이것은 긴 내용을 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 | 바 | 바즈                          
-: | -: | : ----------------------------
  1 | 2 | blah blah blah blah blah blah
  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 | 바 | 바즈
-: | -: | : ---
  1 | 2 | null 
  3 | 4 | 없는

여기 dbfiddle


2
  • 응용 프로그램 관점에서 이것은 게으른 솔루션입니다. 응용 프로그램이 새 열로 수행 할 작업을 자동으로 알지 못할 것입니다.

    데이터 브라우저 응용 프로그램은 데이터의 메타 데이터를 쿼리하고 실행중인 쿼리에서 열을 제외하거나 열 데이터의 하위 집합을 선택할 수 있습니다. 추가하면 새 BLOB를 제외 할 수 있습니다. 특정 행에 대한 BLOB 데이터는 요청시 선택할 수 있습니다.

  • 동적 쿼리를 지원하는 모든 SQL 변형에서 테이블 메타 데이터에 대한 쿼리를 사용하여 쿼리를 작성할 수 있습니다. 귀하의 의도에 따라 이름이 아닌 유형을 기준으로 열을 제외합니다.


2

*SQL-VIEWS에 표시되지 않습니다 ...에서 확인 \d any_view하십시오 psql. 내부 표현을위한 (내관적인) 전처리 가 있습니다.


여기에있는 모든 토론 문제 제안 (질문과 토론에 내재 된)이 실제 "SQL 최적화 문제"가 아니라 프로그래머를위한 구문 설탕 이라는 것을 보여줍니다 . 글쎄, 그것은 프로그래머의 80 %를위한 것입니다.

" introspection으로 사전 구문 분석 "으로 구현할 수 있습니다 SELECT *. 다음 과 같이 SQL-VIEW를 선언 할 때 PostgreSQL이 수행 *하는 작업을 확인하십시오. VIEW 소스 코드 작성).

CREATE VIEW 및 PREPARE 구현

실행 가능한 구현입니다. t필드가있는 테이블 을 가정하십시오 (id serial, name text, the_geom geom).

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)또는 기타.


1

이것은 모든 열을 하나 선택하는 기능입니다. postgresonline.compostgresql 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)
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.