ITPUB??ì3
ITPUB论坛 » MySQL及其它开源数据库 » PostgreSQL INFORMATION_SCHEMA

标题: [转载] PostgreSQL INFORMATION_SCHEMA
离线 hotiice
版主


精华贴数 10
个人空间 0
技术积分 17584 (68)
社区积分 1829 (735)
注册日期 2004-9-9
论坛徽章:26
现任管理团队成员会员2007贡献徽章铁扇公主生肖徽章2007版:虎生肖徽章2007版:羊数据库板块每日发贴之星
生肖徽章2007版:兔2008北京奥运纪念徽章:篮球生肖徽章2007版:牛2008北京奥运纪念徽章:帆船2008北京奥运纪念徽章:游泳设计板块每日发贴之星

发表于 2006-11-24 12:31 
PostgreSQL INFORMATION_SCHEMA

http://www.alberton.info/postgresql_meta_info.html
PostgreSQL INFORMATION_SCHEMA
Following my tutorial on how to extract meta informations from Firebird SQL, I'm now going to show how to retrieve the same informations from PostgreSQL, using the INFORMATION_SCHEMA (available since PostgreSQL 7.4) and with system catalogs (pg_class, pg_user, pg_view, etc).
NB: as you probably know, you can list tables/indices/sequences/views from the command line with the \d{t|i|s|v} command, but here I want to show how to extract these informations using standard SQL queries.


Test data
We need a few sample tables, indices and views to test the following queries, so let's create them. We also create a sample TRIGGER and a function.

-- sample data to test PostgreSQL INFORMATION_SCHEMA

-- TABLE TEST
CREATE TABLE TEST (
  TEST_NAME CHAR(30) NOT NULL,
  TEST_ID INTEGER DEFAULT '0' NOT NULL,
  TEST_DATE TIMESTAMP NOT NULL
);
ALTER TABLE TEST ADD CONSTRAINT PK_TEST PRIMARY KEY (TEST_ID);

-- TABLE TEST2 with some CONSTRAINTs and an INDEX
CREATE TABLE TEST2 (
  ID INTEGER NOT NULL,
  FIELD1 INTEGER,
  FIELD2 CHAR(15),
  FIELD3 VARCHAR(50),
  FIELD4 INTEGER,
  FIELD5 INTEGER,
  ID2 INTEGER NOT NULL
);
ALTER TABLE TEST2 ADD CONSTRAINT PK_TEST2 PRIMARY KEY (ID2);
ALTER TABLE TEST2 ADD CONSTRAINT TEST2_FIELD1ID_IDX UNIQUE (ID, FIELD1);
ALTER TABLE TEST2 ADD CONSTRAINT TEST2_FIELD4_IDX UNIQUE (FIELD4);
CREATE INDEX TEST2_FIELD5_IDX ON TEST2(FIELD5);

-- TABLE NUMBERS
CREATE TABLE NUMBERS (
  NUMBER INTEGER DEFAULT '0' NOT NULL,
  EN CHAR(100) NOT NULL,
  FR CHAR(100) NOT NULL
);

-- TABLE NEWTABLE
CREATE TABLE NEWTABLE (
  ID INT DEFAULT 0 NOT NULL,
  SOMENAME VARCHAR (12),
  SOMEDATE TIMESTAMP NOT NULL
);
ALTER TABLE NEWTABLE ADD CONSTRAINT PKINDEX_IDX PRIMARY KEY (ID);
CREATE SEQUENCE NEWTABLE_SEQ INCREMENT 1 START 1;

-- VIEW on TEST
CREATE VIEW "testview"(
  TEST_NAME,
  TEST_ID,
  TEST_DATE
) AS
SELECT *
FROM TEST
WHERE TEST_NAME LIKE 't%';

-- VIEW on NUMBERS
CREATE VIEW "numbersview"(
  NUMBER,
  TRANS_EN,
  TRANS_FR
) AS
SELECT *
FROM NUMBERS
WHERE NUMBER > 100;

-- TRIGGER on NEWTABLE
CREATE FUNCTION add_stamp() RETURNS OPAQUE AS '
    BEGIN
      IF (NEW.somedate IS NULL OR NEW.somedate = 0) THEN
        NEW.somedate := CURRENT_TIMESTAMP;
        RETURN NEW;
      END IF;
    END;
' LANGUAGE 'plpgsql';

CREATE TRIGGER ADDCURRENTDATE
BEFORE INSERT OR UPDATE
ON newtable FOR EACH ROW
  EXECUTE PROCEDURE add_stamp();
List TABLEs
Here's the query that will return the names of the tables defined in the current database:

SELECT relname
  FROM pg_class
WHERE relname !~ '^(pg_|sql_)'
   AND relkind = 'r'; -- using INFORMATION_SCHEMA: SELECT table_name FROM information_schema.tables WHERE table_type = 'BASE TABLE' AND table_schema NOT IN ('pg_catalog', 'information_schema'); List VIEWs
Here's the query that will return the names of the VIEWs defined in the current database:

-- with postgresql 7.2:

SELECT viewname
  FROM pg_views
WHERE viewname !~ '^pg_';

-- with postgresql 7.4 and later:

SELECT viewname
  FROM pg_views
WHERE schemaname NOT IN
       ('pg_catalog', 'information_schema')
   AND viewname !~ '^pg_';

-- using INFORMATION_SCHEMA:

SELECT table_name
  FROM information_schema.tables
WHERE table_type = 'VIEW'
   AND table_schema NOT IN
       ('pg_catalog', 'information_schema')
   AND table_name !~ '^pg_';

-- or

SELECT table_name
  FROM information_schema.views
WHERE table_schema NOT IN ('pg_catalog', 'information_schema')
   AND table_name !~ '^pg_';

List users
SELECT usename
  FROM pg_user;
List INDICES
Here's the query that will return the names of the INDICES defined in the TEST2 table. Unfortunately I have no idea how to extract them from the INFORMATION_SCHEMA. If you do, please let me know.
NB: the CONSTRAINTs are not listed

SELECT relname
  FROM pg_class
WHERE oid IN (
    SELECT indexrelid
      FROM pg_index, pg_class
     WHERE pg_class.relname='test2'
       AND pg_class.oid=pg_index.indrelid
       AND indisunique != 't'
       AND indisprimary != 't'
);
List CONSTRAINTs
Here's the query that will return the names of the CONSTRAINTs defined in the TEST2 table:

SELECT relname
  FROM pg_class
WHERE oid IN (
    SELECT indexrelid
      FROM pg_index, pg_class
     WHERE pg_class.relname='test2'
       AND pg_class.oid=pg_index.indrelid
       AND (   indisunique = 't'
            OR indisprimary = 't'
       )
);

-- with INFORMATION_SCHEMA:

SELECT constraint_name, constraint_type
  FROM information_schema.table_constraints
WHERE table_name = 'test2';

List table fields
Here's the query that will return the names of the fields of the TEST2 table:

SELECT a.attname
  FROM pg_class c, pg_attribute a, pg_type t
WHERE c.relname = 'test2'
   AND a.attnum > 0
   AND a.attrelid = c.oid
   AND a.atttypid = t.oid

-- with INFORMATION_SCHEMA:

SELECT column_name
  FROM information_schema.columns
WHERE table_name = 'test2';
If you want some more info about the field definitions, you can retrieve a larger subset of the fields available in the schema:

  SELECT a.attnum AS ordinal_position,
         a.attname AS column_name,
         t.typname AS data_type,
         a.attlen AS character_maximum_length,
         a.atttypmod AS modifier,
         a.attnotnull AS notnull,
         a.atthasdef AS hasdefault
    FROM pg_class c,
         pg_attribute a,
         pg_type t
   WHERE c.relname = 'test2'
     AND a.attnum > 0
     AND a.attrelid = c.oid
     AND a.atttypid = t.oid
ORDER BY a.attnum;

-- with INFORMATION_SCHEMA:

  SELECT ordinal_position,
         column_name,
         data_type,
         column_default,
         is_nullable,
         character_maximum_length,
         numeric_precision
    FROM information_schema.columns
   WHERE table_name = 'test2'
ORDER BY ordinal_position;
List sequences
A SEQUENCE is an object that automatically generate sequence numbers. A SEQUENCE is often used to ensure a unique value in a PRIMARY KEY that must uniquely identify the associated row.

SELECT relname
  FROM pg_class
WHERE relkind = 'S'
   AND relnamespace IN (
        SELECT oid
          FROM pg_namespace
         WHERE nspname NOT LIKE 'pg_%'
           AND nspname != 'information_schema'
);
List TRIGGERs
SELECT trg.tgname AS trigger_name
  FROM pg_trigger trg, pg_class tbl
WHERE trg.tgrelid = tbl.oid
   AND tbl.relname !~ '^pg_';
-- or
SELECT tgname AS trigger_name
  FROM pg_trigger
WHERE tgname !~ '^pg_';

-- with INFORMATION_SCHEMA:

SELECT DISTINCT trigger_name
  FROM information_schema.triggers
WHERE trigger_schema NOT IN
       ('pg_catalog', 'information_schema');
List only the triggers for a given table:

SELECT trg.tgname AS trigger_name
  FROM pg_trigger trg, pg_class tbl
WHERE trg.tgrelid = tbl.oid
   AND tbl.relname = 'newtable';

-- with INFORMATION_SCHEMA:

SELECT DISTINCT trigger_name
  FROM information_schema.triggers
WHERE event_object_table = 'newtable'
   AND trigger_schema NOT IN
       ('pg_catalog', 'information_schema');

Show more informations about the trigger definitions:

SELECT trg.tgname AS trigger_name,
       tbl.relname AS table_name,
       p.proname AS function_name,
       CASE trg.tgtype & cast(2 as int2)
         WHEN 0 THEN 'AFTER'
         ELSE 'BEFORE'
       END AS trigger_type,
       CASE trg.tgtype & cast(28 as int2)
         WHEN 16 THEN 'UPDATE'
         WHEN  8 THEN 'DELETE'
         WHEN  4 THEN 'INSERT'
         WHEN 20 THEN 'INSERT, UPDATE'
         WHEN 28 THEN 'INSERT, UPDATE, DELETE'
         WHEN 24 THEN 'UPDATE, DELETE'
         WHEN 12 THEN 'INSERT, DELETE'
       END AS trigger_event
  FROM pg_trigger trg,
       pg_class tbl,
       pg_proc p
WHERE trg.tgrelid = tbl.oid
   AND trg.tgfoid = p.oid
   AND tbl.relname !~ '^pg_';

-- with INFORMATION_SCHEMA:

SELECT *
  FROM information_schema.triggers
WHERE trigger_schema NOT IN
       ('pg_catalog', 'information_schema');
List FUNCTIONs
SELECT proname
  FROM pg_proc pr,
       pg_type tp
WHERE tp.oid = pr.prorettype
   AND pr.proisagg = FALSE
   AND tp.typname <> 'trigger'
   AND pr.pronamespace IN (
       SELECT oid
         FROM pg_namespace
        WHERE nspname NOT LIKE 'pg_%'
          AND nspname != 'information_schema'
);

-- with INFORMATION_SCHEMA:

SELECT routine_name
  FROM information_schema.routines
WHERE specific_schema NOT IN
       ('pg_catalog', 'information_schema')
   AND type_udt_name != 'trigger';
Albe Laurenz sent me the following function that is even more informative: for a function name and schema, it selects the position in the argument list, the direction, the name and the data-type of each argument. This procedure requires PostgreSQL 8.1 or later.

CREATE OR REPLACE FUNCTION public.function_args(
  IN funcname character varying,
  IN schema character varying,
  OUT pos integer,
  OUT direction character,
  OUT argname character varying,
  OUT datatype character varying)
RETURNS SETOF RECORD AS $$DECLARE
  rettype character varying;
  argtypes oidvector;
  allargtypes oid[];
  argmodes "char"[];
  argnames text[];
  mini integer;
  maxi integer;
BEGIN
  /* get object ID of function */
  SELECT INTO rettype, argtypes, allargtypes, argmodes, argnames
         CASE
         WHEN pg_proc.proretset
         THEN 'setof ' || pg_catalog.format_type(pg_proc.prorettype, NULL)
         ELSE pg_catalog.format_type(pg_proc.prorettype, NULL) END,
         pg_proc.proargtypes,
         pg_proc.proallargtypes,
         pg_proc.proargmodes,
         pg_proc.proargnames
    FROM pg_catalog.pg_proc
         JOIN pg_catalog.pg_namespace
         ON (pg_proc.pronamespace = pg_namespace.oid)
   WHERE pg_proc.prorettype <> 'pg_catalog.cstring':g_catalog.regtype
     AND (pg_proc.proargtypes[0] IS NULL
      OR pg_proc.proargtypes[0] <> 'pg_catalog.cstring':g_catalog.regtype)
     AND NOT pg_proc.proisagg
     AND pg_proc.proname = funcname
     AND pg_namespace.nspname = schema
     AND pg_catalog.pg_function_is_visible(pg_proc.oid);

  /* bail out if not found */
  IF NOT FOUND THEN
    RETURN;
  END IF;

  /* return a row for the return value */
  pos = 0;
  direction = 'o'::char;
  argname = 'RETURN VALUE';
  datatype = rettype;
  RETURN NEXT;

  /* unfortunately allargtypes is NULL if there are no OUT parameters */
  IF allargtypes IS NULL THEN
    mini = array_lower(argtypes, 1); maxi = array_upper(argtypes, 1);
  ELSE
    mini = array_lower(allargtypes, 1); maxi = array_upper(allargtypes, 1);
  END IF;
  IF maxi < mini THEN RETURN; END IF;

  /* loop all the arguments */
  FOR i IN mini .. maxi LOOP
    pos = i - mini + 1;
    IF argnames IS NULL THEN
      argname = NULL;
    ELSE
      argname = argnames;
    END IF;
    IF allargtypes IS NULL THEN
      direction = 'i'::char;
      datatype = pg_catalog.format_type(argtypes, NULL);
    ELSE
      direction = argmodes;
      datatype = pg_catalog.format_type(allargtypes, NULL);
    END IF;
    RETURN NEXT;
  END LOOP;

  RETURN;
END;$$ LANGUAGE plpgsql STABLE STRICT SECURITY INVOKER;
COMMENT ON FUNCTION public.function_args(character varying, character
varying)
IS $$For a function name and schema, this procedure selects for each
argument the following data:
- position in the argument list (0 for the return value)
- direction 'i', 'o', or 'b'
- name (NULL if not defined)
- data type$$;
What else?
If you'd like to see some other example queries, or have some comments and/or suggestions, just drop me a mail (you can find my address in the footer of this page) and I'll add them to this list.
HTH.


__________________
①②⑧

只看该作者    顶部
 
    

相关内容


CopyRight 1999-2006 itpub.net All Right Reserved.
北京皓辰网域网络信息技术有限公司. 版权所有
E-mail:Webmaster@itpub.net
京ICP证:060528号 联系我们 法律顾问