postgresql WITH语句添加空记录以进行报告

时间:2013-05-13 09:53:25

标签: sql postgresql report with-statement

我正在写一个postgresql数据库(9.2)的请求来描述所有模式表的结构。 为了使请求的结果更具可读性,我想在行之后添加一个epmty记录,对应于确切的表。

我认为最简单的方法就是使用WITH语句。所以我在这里遇到了一些问题。

当前结果行集部分:

"table_name"    "column_name"   "format_type"   "description"   "is_pk" "is_nullable"   "foreign_table" "foreign_column"
"active_keys"   "TABLE" ""  "Login activation keys" ""  ""  ""  ""
""  "Key"   "character varying(900)"    "Activation key"    "PK"    ""  ""  ""
""  "LoginID"   "bigint"    "Activated login   ""   "Y" ""  ""
"addresses" "TABLE" ""  ""  ""  ""  ""  ""
""  "IDRec" "integer"   ""  ""  ""  ""  ""

通缉结果行集部分:

"table_name"    "column_name"   "format_type"   "description"   "is_pk" "is_nullable"   "foreign_table" "foreign_column"
"active_keys"   "TABLE" ""  "Login activation keys" ""  ""  ""  ""
""  "Key"   "character varying(900)"    "Activation key"    "PK"    ""  ""  ""
""  "LoginID"   "bigint"    "Activated login   ""   "Y" ""  ""

""  ""  ""  ""  ""  ""  ""  "" -- <-- empty record to determine next table description block

"addresses" "TABLE" ""  ""  ""  ""  ""  ""
""  "IDRec" "integer"   ""  ""  ""  ""  ""

报告SQL查询(对于我的架构名称空间'stm'):

with  meta_constr_pk as (
    SELECT DISTINCT tc.constraint_name,
        tc.table_name,
        kcu.column_name,
        tc.constraint_type
    FROM information_schema.table_constraints tc
    JOIN information_schema.key_column_usage kcu ON tc.constraint_name::text = kcu.constraint_name::text
    WHERE tc.constraint_type::text = 'PRIMARY KEY' ::text
    ORDER BY tc.table_name ),
meta_constr_fk as (
    SELECT DISTINCT tc.table_name,
        kcu.column_name,
        ccu.table_name AS foreign_table_name,
        ccu.column_name AS foreign_column_name,
        tc.constraint_type
    FROM information_schema.table_constraints tc
    JOIN information_schema.key_column_usage kcu ON tc.constraint_name::text = kcu.constraint_name::text
    JOIN information_schema.constraint_column_usage ccu ON ccu.constraint_name::text = tc.constraint_name::text
    WHERE tc.constraint_type::text = 'FOREIGN KEY' ::text
    ORDER BY tc.table_name ),
main_select AS (
    select    case when a.attname = 'tableoid' then c.relname else '' end as table_name,
        replace(a.attname, 'tableoid', 'TABLE') as column_name,
        replace(format_type(a.atttypid, a.atttypmod), 'oid', '') as format_type,   
        coalesce( coalesce( col_description(c.oid, a.attnum),
        obj_description(c.oid)), '' ) as description,
        case when pk.constraint_type is not null then 'PK' else '' end  is_pk,
        case when col.is_nullable = 'YES' then 'Y' else '' end is_nullable,  
        coalesce( fk.foreign_table_name, '') foreign_table,
        coalesce(fk.foreign_column_name, '') foreign_column
    from pg_class c
    join pg_attribute a on (a.attrelid = c.oid)
    join pg_namespace n on (n.oid = c.relnamespace)
    left join information_schema.columns col on (col.table_name = c.relname and col.column_name = a.attname )   
    left join meta_constr_pk pk on (col.table_name = pk.table_name and col.column_name = pk.column_name )
    left join meta_constr_fk fk on (col.table_name = fk.table_name and col.column_name = fk.column_name )
    where
        n.nspname = 'stm' and c.relkind = 'r'::"char" 
        and ( a.attnum >= 0 or a.attnum = -7 ) -- "-7" for tableoid 
    order by c.relname, COALESCE( col.ordinal_position, 0 )
)
select *
from main_select m;

此外,任何查询简化提示都会被感激接受!

2 个答案:

答案 0 :(得分:0)

  

为了使请求的结果更具可读性,我想在行之后添加一个epmty记录,对应于确切的表。

这是一个演示级别的问题。它与输出的外观有关,而不是输出

这意味着您的报告工具可以更好地处理它,而不是通过SQL处理。 SQL提供数据;报告工具提供布局。

答案 1 :(得分:0)

您可以使用这样的特殊表交叉加入查询:

CROSS JOIN (VALUES(0),(1)) AS l(line)

然后使它成为l.line = 1仅与连接表名的行连接,如果l.line = 1,则不会显示该名称:

WITH  meta_constr_pk AS (
    SELECT DISTINCT tc.constraint_name,
        tc.table_name,
        kcu.column_name,
        tc.constraint_type
    FROM information_schema.table_constraints tc
    JOIN information_schema.key_column_usage kcu ON tc.constraint_name::text = kcu.constraint_name::text
    WHERE tc.constraint_type::text = 'PRIMARY KEY' ::text
    ORDER BY tc.table_name ),
meta_constr_fk AS (
    SELECT DISTINCT tc.table_name,
        kcu.column_name,
        ccu.table_name AS foreign_table_name,
        ccu.column_name AS foreign_column_name,
        tc.constraint_type
    FROM information_schema.table_constraints tc
    JOIN information_schema.key_column_usage kcu ON tc.constraint_name::text = kcu.constraint_name::text
    JOIN information_schema.constraint_column_usage ccu ON ccu.constraint_name::text = tc.constraint_name::text
    WHERE tc.constraint_type::text = 'FOREIGN KEY' ::text
    ORDER BY tc.table_name ),
main_select AS (
    SELECT
  CASE WHEN a.attname = 'tableoid' AND l.line=0 THEN c.relname ELSE '' END AS TABLE_NAME,
        CASE WHEN l.line=0 THEN replace(a.attname, 'tableoid', 'TABLE') ELSE '' END AS COLUMN_NAME,
        replace(format_type(a.atttypid, a.atttypmod), 'oid', '') AS format_type,
        coalesce( coalesce( col_description(c.oid, a.attnum),
        obj_description(c.oid)), '' ) AS description,
        CASE WHEN pk.constraint_type IS NOT NULL THEN 'PK' ELSE '' END  is_pk,
        CASE WHEN col.is_nullable = 'YES' THEN 'Y' ELSE '' END is_nullable,
        coalesce( fk.foreign_table_name, '') foreign_table,
        coalesce(fk.foreign_column_name, '') foreign_column
    FROM pg_class c
    CROSS JOIN (VALUES(0),(1)) AS l(line)
    JOIN pg_attribute a ON (a.attrelid = c.oid) AND (l.line=0 OR (l.line=1 AND a.attname = 'tableoid'))
    JOIN pg_namespace n ON (n.oid = c.relnamespace) --AND l.line=0
    LEFT JOIN information_schema.columns col ON (col.TABLE_NAME = c.relname AND col.COLUMN_NAME = a.attname ) AND l.line=0
    LEFT JOIN meta_constr_pk pk ON (col.TABLE_NAME = pk.TABLE_NAME AND col.COLUMN_NAME = pk.COLUMN_NAME ) AND l.line=0
    LEFT JOIN meta_constr_fk fk ON (col.TABLE_NAME = fk.TABLE_NAME AND col.COLUMN_NAME = fk.COLUMN_NAME ) AND l.line=0
    WHERE
      c.relkind = 'r'::"char"
      AND
      n.nspname = 'public'
      AND
      ( a.attnum >= 0 OR a.attnum = -7) -- "-7" for tableoid
    ORDER BY c.relname, l.line, COALESCE( col.ordinal_position, 0 )
)
SELECT *
FROM main_select m;

fiddle(显示l.line以便于理解)

这种方法的唯一问题是你在表的末尾也得到一个空行,这可以通过使用窗口函数row_number()来避免。