주어진 스키마에 테이블이 있는지 확인하는 방법


149

Postgres 8.4 이상 데이터베이스에는 public스키마의 공통 테이블과 스키마의 회사 별 테이블이 company있습니다.
company스키마 이름은 항상 'company'회사 번호로 시작 하고 회사 번호로 끝납니다.
따라서 다음과 같은 스키마가있을 수 있습니다.

public
company1
company2
company3
...
companynn

응용 프로그램은 항상 단일 회사에서 작동합니다.
는 다음 search_path과 같이 odbc 또는 npgsql 연결 문자열에 따라 지정됩니다.

search_path='company3,public'

주어진 테이블이 지정된 companyn스키마에 존재하는지 어떻게 확인 합니까?

예 :

select isSpecific('company3','tablenotincompany3schema')

반환해야 false하며

select isSpecific('company3','tableincompany3schema')

반환해야합니다 true.

어쨌든 함수는 companyn다른 스키마가 아닌 전달 된 스키마 만 확인해야 합니다.

주어진 테이블이 public전달 된 스키마와 둘 모두에 존재 하면 함수는을 반환해야합니다 true.
Postgres 8.4 이상에서 작동합니다.

답변:


284

정확히 테스트하려는 대상에 따라 다릅니다 .

정보 스키마?

"테이블이 존재하는지 여부"( 누가 묻든 관계없이) 를 찾으려면 정보 스키마 ( information_schema.tables)를 쿼리하는 것은 정확하지 않습니다 . 문서 당 ) :

현재 사용자가 (소유자 또는 일부 권한을 가지고) 액세스 할 수있는 테이블 및 뷰만 표시됩니다.

@kong제공 한 쿼리 는 다음을 반환 할 수 있습니다.FALSE 있지만 테이블은 여전히 ​​존재할 수 있습니다. 그것은 질문에 대답합니다 :

테이블 (또는 뷰)이 있는지 확인하고 현재 사용자가 테이블에 액세스 할 수 있습니까?

SELECT EXISTS (
   SELECT FROM information_schema.tables 
   WHERE  table_schema = 'schema_name'
   AND    table_name   = 'table_name'
   );

정보 스키마는 주요 버전과 다른 RDBMS간에 이식성을 유지하는 데 주로 유용합니다. 그러나 Postgres는 표준을 준수하기 위해 정교한 뷰를 사용해야하기 때문에 구현 속도가 느립니다 information_schema.tables. 그리고 OID와 같은 일부 정보는 시스템 카탈로그에서 번역시 손실됩니다. 실제로 모든 정보를 전달 .

시스템 카탈로그

당신의 질문은 :

테이블이 있는지 확인하는 방법?

SELECT EXISTS (
   SELECT FROM pg_catalog.pg_class c
   JOIN   pg_catalog.pg_namespace n ON n.oid = c.relnamespace
   WHERE  n.nspname = 'schema_name'
   AND    c.relname = 'table_name'
   AND    c.relkind = 'r'    -- only tables
   );

시스템 카탈로그 pg_classpg_namespace직접 사용하면 훨씬 빠릅니다. 그러나 설명서에 따라pg_class :

카탈로그 pg_class카탈로그 테이블과 열을가하거나 테이블에 다른 유사하다 다른 대부분의 모든 것을. 여기에는 인덱스 (또는 참조 pg_index), 시퀀스 , , 구체화 된 뷰 , 복합 유형TOAST 테이블이 포함됩니다. ;

이 특정 질문에 대해 시스템보기를pg_tables 사용할 수도 있습니다 . 주요 Postgres 버전에서 조금 더 간단하고 이식성이 뛰어납니다 (이 기본 쿼리에는 거의 관심이 없습니다).

SELECT EXISTS (
   SELECT FROM pg_tables
   WHERE  schemaname = 'schema_name'
   AND    tablename  = 'table_name'
   );

식별자는 모두 고유해야 합니다 위에서 언급 한 개체 합니다. 물어보고 싶은 경우 :

주어진 스키마에서 테이블 또는 유사한 객체의 이름이 사용되는지 확인하는 방법은 무엇입니까?

SELECT EXISTS (
   SELECT FROM pg_catalog.pg_class c
   JOIN   pg_catalog.pg_namespace n ON n.oid = c.relnamespace
   WHERE  n.nspname = 'schema_name'
   AND    c.relname = 'table_name'
   );

대안 : 캐스트 regclass

SELECT 'schema_name.table_name'::regclass

예외를 발생 제 (검증을 거친 스키마) 테이블 (또는 그 이름을 점유하는 다른 개체)가 존재하지 않는 경우.

테이블 이름을 스키마로 한정하지 않으면 캐스트는 regclass기본적으로로 설정되어 search_path발견 된 첫 번째 테이블에 대한 OID를 반환합니다. 시스템 스키마 pg_catalogpg_temp (현재 세션의 임시 객체에 대한 스키마)는 자동으로의 일부입니다 search_path.

이것을 사용하고 함수에서 가능한 예외를 잡을 수 있습니다. 예:

위와 같은 쿼리는 가능한 예외를 피하므로 약간 더 빠릅니다.

to_regclass(rel_name) Postgres 9.4 이상

훨씬 간단 해졌습니다 :

SELECT to_regclass('schema_name.table_name');

캐스트와 동일 하지만 반환합니다 ...

... 이름을 찾지 못하면 오류가 발생하지 않고 null


4
쉘에서 :[[ `psql dbname -tAc "SELECT EXISTS (SELECT 1 FROM information_schema.tables WHERE table_schema = 'ejabberd' AND table_name = 'users');"` = 't' ]]
brauliobo

1
pg_tables를 사용하지 않는 이유가 있습니까?
m0meni

1
pg_tables실제로 "테이블이 있는지 확인하는 방법"에 대한 좋은 아이디어입니다. (점검 전용 테이블 . 다른 목적을 위해, 같은 위에서 설명되지 또한 것은, pg_tables여러 테이블을 포함하는 도면이다 ( pg_class, pg_namespace, pg_tablespace), 조금 더 비싼하는 가장 중요한 이유는. 내가 쿼리에 사용하고 pg_class직접하지 않았다 pg_tables이 답변을 쓸 때를 생각해보십시오 . 감사합니다.
Erwin Brandstetter

1
@ sage88 : 맞아, 내가 틀린 의견을 제거했습니다. pg_my_temp_schema()존재하는 경우 실제 임시 스키마의 OID를 얻는 데 사용할 수 있습니다 . (그러나 뷰 information_schema에는 OID가 포함 되어 있지 않습니다. SELECT nspname FROM pg_namespace WHERE OID = pg_my_temp_schema()) 테스트에는 몇 가지 약점이 있습니다. 올바른 테스트는 다음 table_schema LIKE 'pg\_temp\_%'과 같습니다 table_schema ~ '^pg_temp_\d+$'.
Erwin Brandstetter

1
@PeterKrauss 9.4 이전의 postgres 버전에서 to_regclass 함수를 사용하려고하면 해당 오류가 발생합니다.
9.4


0

PostgreSQL 9.3 이하의 경우 또는 텍스트로 정규화 된 모든 것을 좋아하는 사람

세 내 옛날 SwissKnife 라이브러리의 맛 : relname_exists(anyThing), relname_normalized(anyThing)relnamechecked_to_array(anyThing). 모두 pg_catalog.pg_class 테이블 에서 확인 하고 표준 범용 데이터 유형 ( boolean , text 또는 text [])을 반환합니다 .

/**
 * From my old SwissKnife Lib to your SwissKnife. License CC0.
 * Check and normalize to array the free-parameter relation-name.
 * Options: (name); (name,schema), ("schema.name"). Ignores schema2 in ("schema.name",schema2).
 */
CREATE FUNCTION relname_to_array(text,text default NULL) RETURNS text[] AS $f$
     SELECT array[n.nspname::text, c.relname::text]
     FROM   pg_catalog.pg_class c JOIN pg_catalog.pg_namespace n ON n.oid = c.relnamespace,
            regexp_split_to_array($1,'\.') t(x) -- not work with quoted names
     WHERE  CASE
              WHEN COALESCE(x[2],'')>'' THEN n.nspname = x[1]      AND c.relname = x[2]
              WHEN $2 IS NULL THEN           n.nspname = 'public'  AND c.relname = $1
              ELSE                           n.nspname = $2        AND c.relname = $1
            END
$f$ language SQL IMMUTABLE;

CREATE FUNCTION relname_exists(text,text default NULL) RETURNS boolean AS $wrap$
  SELECT EXISTS (SELECT relname_to_array($1,$2))
$wrap$ language SQL IMMUTABLE;

CREATE FUNCTION relname_normalized(text,text default NULL,boolean DEFAULT true) RETURNS text AS $wrap$
  SELECT COALESCE(array_to_string(relname_to_array($1,$2), '.'), CASE WHEN $3 THEN '' ELSE NULL END)
$wrap$ language SQL IMMUTABLE;
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.