Query goal: | Find surrogate key columns that name does not end with "id_" or start with "id_". |
Query type: | Problem detection (Each row in the result could represent a flaw in the design) |
Query reliability: | Medium (Medium number of false-positive results) |
Query license: | MIT License |
Fixing suggestion: | Rename the column so that its name starts or ends with "id" instead of "code", "nr", or "key". |
Data source: | INFORMATION_SCHEMA+system catalog |
SQL query: | Click on query to copy it
with keys as (select (select nspname from pg_namespace where oid=c.relnamespace) as key_schema, c.relname as key_table, c.oid as key_table_oid, o.conkey AS key_col from pg_constraint o inner join pg_class c on c.oid = o.conrelid where o.contype in ('u', 'p') and cardinality(o.conkey)=1), keys_unnest as (select key_schema, key_table, key_table_oid, key_col, key_col_num, ordin from keys, unnest(keys.key_col) with ordinality as k(key_col_num, ordin)), keys_with_names AS (select key_schema, key_table, a_key.attname as key_col from keys_unnest k inner join pg_attribute a_key on k.key_col_num = a_key.attnum and k.key_table_oid = a_key.attrelid and a_key.attisdropped = false ), fk as (select (select nspname from pg_namespace where oid=c.relnamespace) as key_schema, c.relname as key_table, c.oid as key_table_oid, o.conkey AS key_col from pg_constraint o inner join pg_class c on c.oid = o.conrelid where o.contype='f'), fk_unnest as (select key_schema, key_table, key_table_oid, key_col, key_col_num, ordin from fk, unnest(fk.key_col) with ordinality as k(key_col_num, ordin)), fk_with_names AS (select key_schema, key_table, a_key.attname as key_col from fk_unnest k inner join pg_attribute a_key on k.key_col_num = a_key.attnum and k.key_table_oid = a_key.attrelid and a_key.attisdropped = false), key_not_fk AS (select key_schema, key_table, key_col from keys_with_names except select key_schema, key_table, key_col from fk_with_names) SELECT c.table_schema, c.table_name , c.column_name AS suspicious_column_name FROM information_schema.columns c LEFT JOIN information_schema.domains d USING (domain_schema, domain_name) INNER JOIN information_schema.schemata s ON c.table_schema=s.schema_name WHERE (coalesce (c.column_default, d.domain_default) ILIKE '%nextval%' OR c.is_identity='YES') AND c.data_type IN ('smallint','integer','bigint') AND c.column_name!~'^id_' AND c.column_name!~'_id$' AND (c.table_schema = 'public' OR s.schema_owner<>'postgres') AND EXISTS (SELECT * FROM key_not_fk AS k WHERE k.key_schema=c.table_schema AND k.key_table=c.table_name AND k.key_col=c.column_name) ORDER BY table_schema, table_name; |
SQL query | Description |
---|---|
with keys as (select (select nspname from pg_namespace where oid=c.relnamespace) as key_schema, c.relname as key_table, c.oid as key_table_oid, o.conkey AS key_col from pg_constraint o inner join pg_class c on c.oid = o.conrelid where o.contype in ('u', 'p') and cardinality(o.conkey)=1), keys_unnest as (select key_schema, key_table, key_table_oid, key_col, key_col_num, ordin from keys, unnest(keys.key_col) with ordinality as k(key_col_num, ordin)), keys_with_names AS (select key_schema, key_table, a_key.attname as key_col from keys_unnest k inner join pg_attribute a_key on k.key_col_num = a_key.attnum and k.key_table_oid = a_key.attrelid and a_key.attisdropped = false ), fk as (select (select nspname from pg_namespace where oid=c.relnamespace) as key_schema, c.relname as key_table, c.oid as key_table_oid, o.conkey AS key_col from pg_constraint o inner join pg_class c on c.oid = o.conrelid where o.contype='f'), fk_unnest as (select key_schema, key_table, key_table_oid, key_col, key_col_num, ordin from fk, unnest(fk.key_col) with ordinality as k(key_col_num, ordin)), fk_with_names AS (select key_schema, key_table, a_key.attname as key_col from fk_unnest k inner join pg_attribute a_key on k.key_col_num = a_key.attnum and k.key_table_oid = a_key.attrelid and a_key.attisdropped = false), key_not_fk AS (select key_schema, key_table, key_col from keys_with_names except select key_schema, key_table, key_col from fk_with_names) SELECT format('ALTER TABLE %1$I.%2$I RENAME COLUMN %3$I TO %4$I;', c.table_schema, c.table_name , c.column_name, REGEXP_REPLACE(REGEXP_REPLACE(c.column_name, '_(nr|code|key)$', '_id'),'^(code|key|nr)_','id_')) AS statements FROM information_schema.columns c LEFT JOIN information_schema.domains d USING (domain_schema, domain_name) INNER JOIN information_schema.schemata s ON c.table_schema=s.schema_name WHERE (coalesce (c.column_default, d.domain_default) ILIKE '%nextval%' OR c.is_identity='YES') AND c.data_type IN ('smallint','integer','bigint') AND c.column_name!~'^id_' AND c.column_name!~'_id$' AND (c.table_schema = 'public' OR s.schema_owner<>'postgres') AND EXISTS (SELECT * FROM key_not_fk AS k WHERE k.key_schema=c.table_schema AND k.key_table=c.table_name AND k.key_col=c.column_name) ORDER BY table_schema, table_name; | Rename the column. |
Collection name | Collection description |
---|---|
Find problems automatically | Queries, that results point to problems in the database. Each query in the collection produces an initial assessment. However, a human reviewer has the final say as to whether there is a problem or not . |
Category name | Category description |
---|---|
Naming | Queries of this category provide information about the style of naming. |
Reference |
---|
http://whileicompile.com/2012/03/my-take-on-identifier-semantics-id-vs-no-vs-code-vs-key/ |