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 이상에서 작동합니다.
답변
정확히 테스트하려는 대상에 따라 다릅니다 .
정보 스키마?
“테이블이 존재하는지 여부”( 누가 묻든 관계없이) 를 찾으려면 정보 스키마 ( 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_class
를 pg_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_catalog
와pg_temp
(현재 세션의 임시 객체에 대한 스키마)는 자동으로의 일부입니다 search_path
.
이것을 사용하고 함수에서 가능한 예외를 잡을 수 있습니다. 예:
위와 같은 쿼리는 가능한 예외를 피하므로 약간 더 빠릅니다.
to_regclass(rel_name)
Postgres 9.4 이상
훨씬 간단 해졌습니다 :
SELECT to_regclass('schema_name.table_name');
캐스트와 동일 하지만 반환합니다 …
… 이름을 찾지 못하면 오류가 발생하지 않고 null
답변
아마도 information_schema를 사용 하십시오 :
SELECT EXISTS(
SELECT *
FROM information_schema.tables
WHERE
table_schema = 'company3' AND
table_name = 'tableincompany3schema'
);
답변
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;