postgresql 对不包含列类型的表进行计数

iyfamqjs  于 2023-04-20  发布在  PostgreSQL
关注(0)|答案(3)|浏览(157)

我对SQL非常陌生,并且已经给了一个家庭作业练习,当翻译成这样时听起来是这样的:“For each column type find the number of tables that do not contain this type of column”.我知道如何找到包含至少一种列类型的表的数量:

SELECT Data_Type, COUNT(Table_schema || '.' || table_name)
FROM Information_schema.Columns
GROUP BY Data_Type;

但是,我花了好几个小时才弄清楚如何做与此相反的事情。我试过使用WHERE:

WHERE Data_Type IS NULL

但它给出了相同的结果查询没有这一行.我已经看到解决方案时,计数表与具体命名的列(使用'join'和'not in'),但我不认为这将为这项任务工作.我认为NOT EXISTS可能会工作,但不知道如何实现它.提前感谢!

i7uq4tfw

i7uq4tfw1#

你可以这样做:

with dtypes as (
    select distinct Data_Type
    from Information_schema.Columns
  )
select
  data_type,
  (
    select count(*)
    from Information_schema.tables t
    where not exists (
        select 1
        FROM Information_schema.Columns c2
        WHERE
          c2.Table_schema = t.Table_schema
          and c2.Table_name = t.Table_name
          and c2.Data_Type = d.Data_Type
      )
    AND t.table_type = 'BASE TABLE'
    -- AND t.Table_schema = 'MYSCHEMA' -- in case you want to count tables only from single schema.
  )
from dtypes d

这里CTE dtypes包含数据库中存在的所有类型作为列类型。
然后,对于每一种类型,我们会找到一些表,这些表至少没有一个这种类型的列。
演示here

dfddblmv

dfddblmv2#

下面是解决这个问题的另一种方法:

WITH tc AS (
  SELECT
    t.table_schema,
    t.table_name,
    COUNT(*) OVER (PARTITION BY NULL) AS total_table_cnt
  FROM
    information_schema.tables t
  WHERE
    t.table_type = 'BASE TABLE'
)
SELECT
  c.data_type,
  MAX(tc.total_table_cnt) - COUNT(DISTINCT (c.table_schema, c.table_name)) AS table_cnt
FROM
  tc
  JOIN information_schema.columns c
    ON (tc.table_schema, tc.table_name) = (c.table_schema, c.table_name)
GROUP BY
  c.data_type
ORDER BY
  c.data_type;

这并没有提出任何优于其他方法的主张,而只是作为额外技术的演示。
查询使用公共表表达式(CTE)来确定表集。表达式COUNT(*) OVER (PARTITION BY NULL)同时获得成员的计数,从而避免了额外的子查询。
在主查询中,MAX(tc.total_table_cnt)将总表计数 Package 在聚合函数中,以便它的值可以在分组查询中使用。也可以使用MIN,因为该值对于 tc 中的所有行都是相同的。
COUNT(DISTINCT (c.table_schema, c.table_name))获取至少有一列属于该组数据类型的表的计数。
行构造函数(tc.table_schema, tc.table_name) = (c.table_schema, c.table_name)用于连接条件。在这种情况下,与为每列使用单独的相等比较相比,没有明显的优势,但是当IN操作符或子查询需要多列时,行构造函数非常有用。

ubof19bj

ubof19bj3#

这个问题确实需要更仔细地界定。

  • 要包括哪些表和哪些类型?
  • 是否包括内部数据类型和系统表?
  • varchar(25)varchar不同吗?
  • 分区表怎么样?
  • 物化视图?
  • 是否生成列?
  • 用户类型?...

在我看来,这个查询比基于信息模式的查询快50倍左右:

SELECT col.atttypid::regtype AS data_type
     , tbl.tbls_total - col.tbls_with_type AS tbls_without_that_type
FROM  (
   SELECT a.atttypid::regtype, count(DISTINCT a.attrelid) AS tbls_with_type
   FROM   pg_attribute a
   JOIN   pg_class c ON c.oid = a.attrelid
   WHERE  c.relnamespace = 'public'::regnamespace  -- only user schema(s)
   AND    c.relkind = 'r'
   AND    a.attnum > 0
   AND    NOT a.attisdropped
   GROUP  BY 1
   ) col
CROSS JOIN (
   SELECT  count(*) AS tbls_total
   FROM    pg_class c
   WHERE   c.relnamespace = 'public'::regnamespace  -- only user schema(s)
   AND     relkind = 'r'
   ) tbl
ORDER  BY 2 DESC, 1

基本的方法是计算每种数据类型的 * 现有 * 表,然后从表的总数中减去。
我排除了系统列,并将查询限制在public模式。
有各种不同!
值得注意的是,对information_schema的查询将所有的“ARRAY”类型合并在一起,而我的查询将text[]int[]等作为不同的类型处理。
此外,信息架构不包括分区表(正确地)。您可能希望也可能不希望这样。
关于信息架构与系统目录:

相关:

  • 如何检查给定模式中是否存在表

相关问题