ITPUB??ì3
2010数据库技术大会
ITPUB论坛 » MySQL及其它开源数据库 » PostgreSQL INFORMATION_SCHEMA


您有 2 条公共消息
  • 来自: 公共消息 标题: 3-5月ITPUB数据库 ... 内容: ITPUB与3月和5月分别安排了Oracle 11g DBA和Oracle性能优化培训,以及 ...
  • 来自: 公共消息 标题: ITPUB邮箱已经恢复 内容: ITPUB邮箱用户请注意,邮箱现在已经恢复 web访问地址 http://emai ...

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


    精华贴数 10
    个人空间 0
    技术积分 18451 (71)
    社区积分 1830 (814)
    注册日期 2004-9-9
    论坛徽章:33
    现任管理团队成员ITPUB长老会成员会员2007贡献徽章铁扇公主2010新春纪念徽章2010年世界杯参赛球队:日本
    2010新春纪念徽章祖国60周年纪念徽章生肖徽章2007版:牛生肖徽章2007版:虎生肖徽章2007版:羊数据库板块每日发贴之星

    发表于 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号 联系我们