How do I list all identity columns in a table - postgresql

What query should I use to list all GENERATED { ALWAYS | BY DEFAULT } AS IDENTITY columns in given table in PostgreSQL database?
I would like also like to see whether the column is GENERATED ALWAYS or GENERATED BY DEFAULT.

You can get the list of all generated columns by looking in the pg_attribute table under the attgenerated column:
postgres=# create table abc (
id int GENERATED ALWAYS AS IDENTITY,
height_cm numeric,
height_in numeric GENERATED ALWAYS AS (height_cm / 2.54) STORED);
postgres=# select attname, attidentity, attgenerated
from pg_attribute
where attnum > 0
and attrelid = (select oid from pg_class where relname = 'abc');
attname | attidentity | attgenerated
-----------+-------------+--------------
id | a |
height_cm | |
height_in | | s
(3 rows)
Identity columns are identified in attidentity. More information in the PostgreSQL documentation

Related

Postgres: does updating column value to the same value marks page as dirty?

Consider following scenario in PostgreSQL (any version from 10+):
CREATE TABLE users(
id serial primary key,
name text not null unique,
last_seen timestamp
);
INSERT INTO users(name, last_seen)
VALUES ('Alice', '2019-05-01'),
('Bob', '2019-04-29'),
('Dorian', '2019-05-11');
CREATE TABLE inactive_users(
user_id int primary key references users(id),
last_seen timestamp not null);
INSERT INTO inactive_users(user_id, last_seen)
SELECT id as user_id, last_seen FROM users
WHERE users.last_seen < '2019-05-04'
ON CONFLICT (user_id) DO UPDATE SET last_seen = excluded.last_seen;
Now let's say that I want to insert the same values (execute last statement) multiple times, every now and then. In practice from the database point of view, on conflicting values 90% of the time last_seen column will be updated to the same value it already had. The values of the rows stay the same, so there's no reason to do I/O writes, right? But is this really the case, or will postgres perform corresponding updates even though the actual value didn't change?
In my case the destination table has dozens of millions of rows, but only few hundreds/thousands of them will be really changing on each of the insert calls.
Any UPDATE to a row will actually create a new row (marking the old row deleted/dirty), regardless of the before/after values:
[root#497ba0eaf137 /]# psql
psql (12.1)
Type "help" for help.
postgres=# create table foo (id int, name text);
CREATE TABLE
postgres=# insert into foo values (1,'a');
INSERT 0 1
postgres=# select ctid,* from foo;
ctid | id | name
-------+----+------
(0,1) | 1 | a
(1 row)
postgres=# update foo set name = 'a' where id = 1;
UPDATE 1
postgres=# select ctid,* from foo;
ctid | id | name
-------+----+------
(0,2) | 1 | a
(1 row)
postgres=# update foo set id = 1 where id = 1;
UPDATE 1
postgres=# select ctid,* from foo;
ctid | id | name
-------+----+------
(0,3) | 1 | a
(1 row)
postgres=# select * from pg_stat_user_tables where relname = 'foo';
-[ RECORD 1 ]-------+-------
relid | 16384
schemaname | public
relname | foo
seq_scan | 5
seq_tup_read | 5
idx_scan |
idx_tup_fetch |
n_tup_ins | 1
n_tup_upd | 2
n_tup_del | 0
n_tup_hot_upd | 2
n_live_tup | 1
n_dead_tup | 2
<...>
And according to your example:
postgres=# select ctid,* FROM inactive_users ;
ctid | user_id | last_seen
-------+---------+---------------------
(0,1) | 1 | 2019-05-01 00:00:00
(0,2) | 2 | 2019-04-29 00:00:00
(2 rows)
postgres=# INSERT INTO inactive_users(user_id, last_seen)
postgres-# SELECT id as user_id, last_seen FROM users
postgres-# WHERE users.last_seen < '2019-05-04'
postgres-# ON CONFLICT (user_id) DO UPDATE SET last_seen = excluded.last_seen;
INSERT 0 2
postgres=# select ctid,* FROM inactive_users ;
ctid | user_id | last_seen
-------+---------+---------------------
(0,3) | 1 | 2019-05-01 00:00:00
(0,4) | 2 | 2019-04-29 00:00:00
(2 rows)
Postgres does not do any data validation against the column values -- if you are looking to prevent unnecessary write activity, you will need to surgically craft your WHERE clauses.
Disclosure: I work for EnterpriseDB (EDB)

Getting referenced tables in Postgres

I have a list of foreign keys. I'd like to find out the tables where these FK's point to and the actual key the point to.
I've got a list of FK's like so:
columnName0, columnName1, columnName2
Foreign key references
columnName0 references table0.idTable0
columnName1 references table1.idTable1
columnName2 references table2.idTable2
Some sample tables:
Table0:
idTable0, PK
name
Table1:
idTable1, PK
age
Table2:
idTable2, PK
createdOn
A sample result:
| column | referenced_column | referenced_table |
|-------------|-------------------|------------------|
| columnName0 | idTable0 | table0 |
| columnName1 | idTable1 | table1 |
| columnName2 | idTable2 | table2 |
I'm trying to translate something I do in MySQL like this:
SELECT DISTINCT
COLUMN_NAME AS column,
REFERENCED_COLUMN_NAME AS referenced_column,
REFERENCED_TABLE_NAME AS referenced_table
FROM
INFORMATION_SCHEMA.KEY_COLUMN_USAGE
WHERE
COLUMN_NAME IN (?);
I'm going to have to use straight-up queries (unfortunately, no stored procedures).
You can query pg_constraint. For column names you should lookup pg_attribute. A foreign key may be based on multiple columns, so conkey and confkey of pg_constraint are arrays. You have to unnest the arrays to get a list of column names. Example:
select
conrelid::regclass table_name,
a1.attname column_name,
confrelid::regclass referenced_table,
a2.attname referenced_column,
conname constraint_name
from (
select conname, conrelid::regclass, confrelid::regclass, col, fcol
from pg_constraint c,
lateral unnest(conkey) col,
lateral unnest(confkey) fcol
where contype = 'f' -- foreign keys constraints
) s
join pg_attribute a1 on a1.attrelid = conrelid and a1.attnum = col
join pg_attribute a2 on a2.attrelid = confrelid and a2.attnum = fcol;
table_name | column_name | referenced_table | referenced_column | constraint_name
------------+-------------+------------------+-------------------+------------------------
products | image_id | images | id | products_image_id_fkey
(1 row)
In Postgres 9.4 or later the function unnest() may have multiple arguments and the inner query may look like this:
...
select conname, conrelid::regclass, confrelid::regclass, col, fcol
from pg_constraint c,
lateral unnest(conkey, confkey) u(col, fcol)
where contype = 'f' -- foreign keys constraints
...

How do we get all columns which are the part of sortkey in Redshift

I need to get all columns, which are the part of sortkey in Redshift.
I tried get information using "select * from svv_table_info" but it have only the information of one column only. Can you let me know, how do I get all columns which are the part of Sortkey for a table.
Thanks,
Sanjeev
Thanks all for your help. I already tried "pg_table_def" table to get sortkey and distkey information but I have seen only pg_catalog and Public schema, I just go through the Amazon developer guide and found we need to add schema to search path using below commands:-
show search_path;
set search_path to '$user', 'public', 'NewSchema';
After adding the "NewSchema" in search path I can see sortkey and distkey information for this schema in pg_table_def
Thanks,
Sanjeev
Sanjeev,
A table called pg_table_def has information about the columns.
In the example below, I created a simple table with four columns and used 2 of these columns as my sort key.
As you can see in my query results the "sort key" field shows a number other than 0 if the column is part of a sort key.
dev=# drop table tb1;
DROP TABLE
dev=# create table tb1 (col1 integer, col2 integer, col3 integer, col4 integer) distkey(col1) sortkey(col2, col4);
CREATE TABLE
dev=# select * from pg_table_def where tablename = 'tb1';
schemaname | tablename | column | type | encoding | distkey | sortkey | notnull
------------+-----------+--------+---------+----------+---------+---------+---------
public | tb1 | col1 | integer | none | t | 0 | f
public | tb1 | col2 | integer | none | f | 1 | f
public | tb1 | col3 | integer | none | f | 0 | f
public | tb1 | col4 | integer | none | f | 2 | f
(4 rows)
What about:
select "column", type, encoding, distkey, sortkey, "notnull"
from pg_table_def
where tablename = 'YOURTABLE'
and sortkey <> 0;

PostgreSQL: duplicate key value violates unique constraint on UPDATE command

When doing an UPDATE query, we got the following error message:
ERROR: duplicate key value violates unique constraint "tableA_pkey"
DETAIL: Key (id)=(47470) already exists.
However, our UPDATE query does not affect the primary key. Here is a simplified version:
UPDATE tableA AS a
SET
items = (
SELECT array_to_string(
array(
SELECT b.value
FROM tableB b
WHERE b.a_id = b.id
GROUP BY b.name
),
','
)
)
WHERE
a.end_at BETWEEN now() AND now() - interval '1 day';
We ensured the primary key sequence was already synced:
\d tableA_id_seq
Which produces:
Column | Type | Value
---------------+---------+--------------------------
sequence_name | name | tableA_id_seq
last_value | bigint | 50364
start_value | bigint | 1
increment_by | bigint | 1
max_value | bigint | 9223372036854775807
min_value | bigint | 1
cache_value | bigint | 1
log_cnt | bigint | 0
is_cycled | boolean | f
is_called | boolean | t
Looking for maximum table index:
select max(id) from tableA;
We got a lower value:
max
-------
50363
(1 row)
Have you any idea on why such a behavior? If we exclude the problematic id, it works.
Another strange point is that replacing the previous UPDATE by:
UPDATE tableA AS a
SET
items = (
SELECT array_to_string(
array(
SELECT b.value
FROM tableB b
WHERE b.a_id = b.id
GROUP BY b.name
),
','
)
)
WHERE a.id = 47470;
It works well. Are we missing something?
EDIT: triggers
I have no user-defined triggers on this table:
SELECT t.tgname, c.relname
FROM pg_trigger t
JOIN pg_class c ON t.tgrelid = c.oid
WHERE
c.relname = 'tableA'
AND
t.tgisinternal = false
;
Which returns no row.
Note: I am using psql (PostgreSQL) 9.3.4 version.
Not really sure what was the cause. However, deleting the two (non vital) records corresponding to already existing ids (?) solved the issue.

Checking fillfactor setting for tables and indexes

There is maybe some function to check the fillfactor for indexes and tables? I've tried already \d+ but have basic definition only, without fillfactor value:
Index "public.tab1_pkey"
Column | Type | Definition | Storage
--------+--------+------------+---------
id | bigint | id | plain
primary key, btree, for table "public.tab1"
For tables haven't found anything. If table was created with fillfactor other than default:
CREATE TABLE distributors (
did integer,
name varchar(40),
UNIQUE(name) WITH (fillfactor=70)
)
WITH (fillfactor=70);
Then \d+ distributorsshows non-standard fillfactor.
Table "public.distributors"
Column | Type | Modifiers | Storage | Stats target | Description
--------+-----------------------+-----------+----------+--------------+-------------
did | integer | | plain | |
name | character varying(40) | | extended | |
Indexes:
"distributors_name_key" UNIQUE CONSTRAINT, btree (name) WITH (fillfactor=70)
Has OIDs: no
Options: fillfactor=70
But maybe there is a way to get this value without parsing output?
You need to query the pg_class system table:
select t.relname as table_name,
t.reloptions
from pg_class t
join pg_namespace n on n.oid = t.relnamespace
where t.relname in ('tab11_pkey', 'tab1')
and n.nspname = 'public'
reloptions is an array, with each element containing one option=value definition. But it will be null for relations that have the default options.