How to determine the OID of a Postgres table? - postgresql

Does anyone know how to find the OID of a table in Postgres 9.1?
I am writing an update script that needs to test for the existence of a column in a table before it tries to add the column. This is to prevent errors when running the script repeatedly.

To get a table OID, cast to the object identifier type regclass (while connected to the same DB):
SELECT 'mytbl'::regclass::oid;
This finds the first table (or view, etc.) with the given name along the search_path or raises an exception if not found.
Schema-qualify the table name to remove the dependency on the search path:
SELECT 'myschema.mytbl'::regclass::oid;
In Postgres 9.4 or later you can also use to_regclass('myschema.mytbl'), which doesn't raise an exception if the table is not found:
How to check if a table exists in a given schema
Then you only need to query the catalog table pg_attribute for the existence of the column:
SELECT TRUE AS col_exists
FROM pg_attribute
WHERE attrelid = 'myschema.mytbl'::regclass
AND attname = 'mycol'
AND NOT attisdropped -- no dropped (dead) columns
-- AND attnum > 0 -- no system columns (you may or may not want this)
;

The postgres catalog table pg_class is what you should look at. There should be one row per table, with the table name in the column relname, and the oid in the hidden column oid.
You may also be interested in the pg_attribute catalog table, which includes one row per table column.
See: http://www.postgresql.org/docs/current/static/catalog-pg-class.html and http://www.postgresql.org/docs/current/static/catalog-pg-attribute.html

SELECT oid FROM pg_class WHERE relname = 'tbl_name' AND relkind = 'r';

Just to complete the possibilities I'd like to add that there exists a syntax for dropping columns in order to no error out:
ALTER TABLE mytbl
DROP COLUMN IF EXISTS mycol
See http://www.postgresql.org/docs/9.0/static/sql-altertable.html
Then you can safely add your column.

Related

PostgreSQL n_distinct statistics setting

Are there multiple ways to set n_distinct in PostgreSQL? Both of these seem to be doing the same thing but end up changing a different value within pg_attribute. What is the difference between these two commands?
alter table my_table alter column my_column set (n_distinct = 500);
alter table my_table alter column my_column set statistics 1000;
select
c.relname,
a.attname,
a.attoptions,
a.attstattarget
from
pg_class c
inner join
pg_attribute a
on c.oid = a.attrelid
where
c.relname = 'my_table'
and
a.attname = 'my_column'
order by
c.relname,
a.attname;
Name |Value
-------------|----------------
relname |my_table
attname |my_column
attoptions |{n_distinct=500}
attstattarget|1000
Both of these seem to be doing the same thing
Why would you say that? Both commands are obviously distinct. Both are related to column statistics and query planning. But they do very different things.
The statistics target ...
controls the level of detail of statistics accumulated for this column by ANALYZE. See:
Check statistics targets in PostgreSQL
Basics in the manual.
Setting n_distinct is something completely different. It means hard-coding the number (or ratio) of distinct values to expect for the given column. (But only effective after the next ANALYZE.)
Related answer on dba.SE with more on n_distinct:
Very bad query plan in PostgreSQL 9.6

Query Constraint Clauses With Schema and Table (Postgres)

I am trying to query the constraint clauses along with schema and table in postgres. I've gotten as far as identifying information_schema.check_constraints as a useful table. The problem is that doing
select *
from information_schema.check_constraints
Results in constraint_catalog, constraint_schema, constraint_name, check_clause. The check_clause is what I want and this table also gives me the constraint_schema. However, it does not give the table that this constraint is defined on. In my current database, I have constraints with the same name defined on different tables within the same schema (which is in it of itself perhaps poor design but what I need to deal with). Is it possible to get the table name here as well?
select
conname,
connamespace::regnamespace as schemaname,
conrelid::regclass as tablename,
consrc as checkclause,
pg_get_constraintdef(oid) as definition
from
pg_constraint
where
contype = 'c'
and conrelid <> 0; -- to get only table constraints
About pg_constraint
About Object Identifier Types

Why does a PostgreSQL SELECT query return different results when a schema name is specified?

I have a PostgreSQL database table with 4 columns - labeled column_a, column_b, etc. I want to query this table with a simple select query:
select * from table_name;
I get a handful of results looking like:
column_a | column_b
---------+---------
'a value'|'b_value'
But when I use this query:
select * from schema_name.table_name;
I get the full result:
column_a | column_b | column_c | column_d
---------+----------+----------+---------
'a value'|'b value' |'c value' |'d_value'
Columns c and d were added at a later date, after initial table creation. My question is: Why would the database ignore the later columns when the schema name is left out of the select query?
Table names are not unique within a database in Postgres. There can be any number of tables named 'table_name' in different schemas - including the temporary schema, which always comes first unless you explicitly list it after other schemas in the search_path. Obviously, there are multiple tables named table_name. You must understand the role of the search_path to interpret this correctly:
How does the search_path influence identifier resolution and the "current schema"
The first table lives in a schema that comes before schema_name in your search_path (or schema_name is not listed there at all). So the unqualified table name is resolved to this table (or view). Check the list of tables named 'table_name' that your current role has access to in your database:
SELECT *
FROM information_schema.tables
WHERE table_name = 'table_name';
Views are just special tables with an attached RULE internally. They could play the same role as a regular table and are included in the above query.
Details:
How to check if a table exists in a given schema

Add Column If Not Exists in Postgresql [duplicate]

This question already has answers here:
How to add column if not exists on PostgreSQL?
(11 answers)
Closed 8 years ago.
Is postgresql (9.3.2) can do check the existence of a column before add a new column?
I don't want to create a function just for to check the existence.
Just simply like this :
ALTER TABLE IF NOT EXISTS table_name ADD COLUMN column_name data_type;
You'll need to write your own stored procedure in Plpgsql to check if the table has this column. For this you'll need the tables PG_ATTRIBUTE and PG_CLASS where Postgres stores the schema metadata and in particular the information about columns and tables respectively.
The query whose result you need to check in your stored procedure would be a JOIN like:
SELECT A.ATTNAME FROM PG_ATTRIBUTE A, PG_CLASS C
WHERE A.ATTRELID = C.OID AND A.ATTNAME = 'column_name_check_if_exists' AND C.relname= 'table_name' ;
In DDL, you can only:
Add columns
Remove columns
Add constraints
Remove constraints
Change default values
Change column data types
Rename columns
Rename tables
ALTER TABLE: SYNOPSIS AND EXAMPLES -> http://www.postgresql.org/docs/9.3/static/sql-altertable.html
For validations... you need make "PL/SQL"
So, there is no such query. I should using PLPGSQL.

ERROR: could not read block 4707 of relation 1663/16384/16564: Success

I am using psql 8.1.18 on Glassfishserver. I have a query like this:
select ip,round((select sum(t1.size) from table t1))
from table
where date > '2011.07.29'
and date < '2011.07.30'
and ip = '255.255.255.255'
group by ip;
When I run this query I got this error:
ERROR: could not read block 4707 of relation 1663/16384/16564: Success
However this query works fine:
select ip,round(sum(size)/175)
from table
where date > '2011.07.29'
and l_date < '2011.07.30'
and ip = '255.255.255.255'
group by ip;
I think it might be a database error and I need to restore the table from the backup, maybe. But first I need to learn where this corrupted data exist. Does anyone know how to find 1663/16384/16564 relation? Or 4707 block?
EDIT:
I tried this code:
select relname , relfilenode from pg_class where relname in ('1663','16384','16564');
but it returns:
relname | relfilenode
---------+-------------
(0 rows)
It looks like there are bad blocks in a table or an index.
To find the bad data, Maybe you can query pg_class views ;
select oid,relname from pg_class where oid =1663 or oid=16564;
just see what's the result!
IF the result is an index, just recreate the corrupted index;
IF the result is a table , than it means that there are some data of the table is damaged,
you can set the parameter "zero_damaged_pages" to on to by pass those corrupted data or
restore the table from your recently backup set !
more information about the parameter "zero_damaged_pages"
http://www.postgresql.org/docs/9.0/static/runtime-config-developer.html