Issue in my Dynamic Query - postgresql

select * from pg_tables where schemaname ='reports' and tablename like '%enhancedreports03_0%' order by tablename;
schemaname | tablename | tableowner |
tablespace | hasindexes | hasrules | hastriggers
------------+--------------------------------+---------------------+--------------+------------+----------+------------- reports | enhancedreports03_0_1970_01_01 | ss_agent_summarizer |
rpt_data_tbs | t | f | f reports |
enhancedreports03_0_2013_10_08 | ss_agent_summarizer | rpt_data_tbs |
t | f | f
Check constraints:
"enhancedreports03_0_1970_01_01_check" CHECK (0::double precision >= date_part('epoch'::text, '1970-01-01'::date) AND 0::double precision < date_part('epoch'::text, '1970-01-02'::date))
I need to drop the constraints in both the tables..So i tried an dynamic query to generate the result set...
select 'ALTER TABLE '||schemaname ||'.'||tablename||' DROP CONSTRAINT '||conname||'' from pg_tables a, pg_constraint b
where schemaname ='reports' and tablename like '%enhancedreports03_0%' and conname like '%enhancedreports03_0_%' order by tablename;
?column?
ALTER TABLE reports.enhancedreports03_0_1970_01_01 DROP CONSTRAINT
enhancedreports03_0_1970_01_01_check ALTER TABLE
reports.enhancedreports03_0_1970_01_01 DROP CONSTRAINT
enhancedreports03_0_2013_10_08_check ALTER TABLE
reports.enhancedreports03_0_1970_01_01 DROP CONSTRAINT
enhancedreports03_0_2013_10_08_check ALTER TABLE
reports.enhancedreports03_0_1970_01_01 DROP CONSTRAINT
enhancedreports03_0_2013_10_08_check ALTER TABLE
reports.enhancedreports03_0_2013_10_08 DROP CONSTRAINT
enhancedreports03_0_1970_01_01_check ALTER TABLE
reports.enhancedreports03_0_2013_10_08 DROP CONSTRAINT
enhancedreports03_0_2013_10_08_check ALTER TABLE
reports.enhancedreports03_0_2013_10_08 DROP CONSTRAINT
enhancedreports03_0_2013_10_08_check ALTER TABLE
reports.enhancedreports03_0_2013_10_08 DROP CONSTRAINT
enhancedreports03_0_2013_10_08_check
(8 rows)
I need the result set to be like this
ALTER TABLE reports.enhancedreports03_0_1970_01_01 DROP CONSTRAINT enhancedreports03_0_1970_01_01_check
ALTER TABLE reports.enhancedreports03_0_2013_10_08 DROP CONSTRAINT enhancedreports03_0_2013_10_08_check
Thanks in advance
Abdul

Try to query information_schema.table_constraints where you can query for table directly instead:
select
*
from
information_schema.table_constraints
where
table_name like 'enhancedreports03_0_%%'
order by
table_name;
The problem with your query is that you are creating cross join because of missing join between pg_tables and pg_constraint.
Easiest would be to use:
select
'ALTER TABLE '||table_schema ||'.'||table_name||
' DROP CONSTRAINT '||constraint_name||';'
from
information_schema.table_constraints
where
table_schema ='reports'
and table_name like '%enhancedreports03_0%'
and constraint_name like '%enhancedreports03_0_%'
order by
table_name;
Documentation
If you would like to use pg catalog, then you have to join tables properly:
select
relname,
conname
from
pg_class pcl
join pg_constraint pco on (pcl.oid = pco.conrelid)
where
relname like 'enhancedreports03_0_%'

I have check your code in my system it worked absolutely fine and give out put u want so i have add one ; at the end hope this will help you.
select 'ALTER TABLE '||schemaname ||'.'||tablename||' DROP CONSTRAINT '||conname||';' from pg_tables a, pg_constraint b
where schemaname ='reports' and tablename like '%enhancedreports03_0%' and conname like '%enhancedreports03_0_%' order by tablename;

Related

PostgreSQL: Alter all tables returned by a select query

I have this query running on a postgres 11.2 db:
SELECT relname
FROM pg_stat_user_tables
WHERE n_mod_since_analyze=0 AND relname LIKE '%'
AND relname NOT IN (SELECT relname FROM pg_class WHERE array_length(reloptions,1)>0);
That returns a list of tables I need to disable autovacuum for. I'm trying to come up with a way to run ALTER TABLE pg_stat_user_tables.relname SET (autovacuum_enabled = false); on all tables returned by my query statement. Googling keeps bringing me back to altering table columns. Is it possible to just take the table names returned from this query and pass it to ALTER TABLE?
Try with psql CLI and \gexec internal command:
SELECT format('ALTER TABLE %s SET (autovacuum_enabled = false);',lt.relname)
FROM
(
SELECT relname
FROM pg_stat_user_tables
WHERE n_mod_since_analyze=0
AND relname LIKE '%'
AND relname NOT IN (SELECT relname FROM pg_class WHERE array_length(reloptions,1)>0)
) lt;
\gexec
Execution output:
ALTER TABLE p SET (autovacuum_enabled = false);
ALTER TABLE
ALTER TABLE t1 SET (autovacuum_enabled = false);
ALTER TABLE
ALTER TABLE t2 SET (autovacuum_enabled = false);
ALTER TABLE

PostgreSQL: Drop column and recreate dependent views

I have below test table and dependent views created.
create table test_col_drp (col1 varchar(100), col2 varchar(100), col3 varchar(100));
create view test_col_drp_vw1 as select col1 col1_vw1, col2 col2_vw1, col3 col3_vw1 from test_col_drp;
create view test_col_drp_vw2 as select col1_vw1 col1_vw2, col2_vw1 col2_vw2, col3_vw1 col3_vw2 from test_col_drp_vw1;
I'm trying to drop a column from the table but getting below error:
alter table test_col_drp drop column col3;
ERROR: cannot drop table test_col_drp column col3 because other objects depend on it
DETAIL: view test_col_drp_vw1 depends on table test_col_drp column col3 view test_col_drp_vw2 depends on view test_col_drp_vw1
HINT: Use DROP ... CASCADE to drop the dependent objects too.
********** Error **********
What would be the best way to drop the column and recreate all the dependent views?
Working on:
PostgreSQL 9.6.6 on x86_64-pc-mingw64, compiled by gcc.exe (Rev5, Built by MSYS2 project) 4.9.2, 64-bit
Windows 10
First, you have to drop the views. Then, execute the alter table and finally create the views again. See:
-- This is what you have in your database
create table test_col_drp (col1 varchar(100), col2 varchar(100), col3 varchar(100));
create view test_col_drp_vw1 as select col1 col1_vw1, col2 col2_vw1, col3 col3_vw1 from test_col_drp;
create view test_col_drp_vw2 as select col1_vw1 col1_vw2, col2_vw1 col2_vw2, col3_vw1 col3_vw2 from test_col_drp_vw1;
-- drop views and alter table
drop view test_col_drp_vw2;
drop view test_col_drp_vw1;
alter table test_col_drp drop column col3;
-- creating the views again without col3
create view test_col_drp_vw1 as select col1 col1_vw1, col2 col2_vw1 from test_col_drp;
create view test_col_drp_vw2 as select col1_vw1 col1_vw2, col2_vw1 col2_vw2 from test_col_drp_vw1;
An alternative is to use the drop cascade. In this case, you do not need to drop each view individually but you still need to recreate them:
alter table test_col_drp drop column col3 cascade;
-- creating the views again without col3
create view test_col_drp_vw1 as select col1 col1_vw1, col2 col2_vw1 from test_col_drp;
create view test_col_drp_vw2 as select col1_vw1 col1_vw2, col2_vw1 col2_vw2 from test_col_drp_vw1;
Another option is to create a SQL command that generates your alter table using cascade and the create view:
with query_result as (
SELECT dependent_ns.nspname as dependent_schema
, dependent_view.relname as dependent_view
, source_ns.nspname as source_schema
, source_table.relname as source_table
, pg_attribute.attname as column_name
, row_number() over() as id
FROM pg_depend
JOIN pg_rewrite ON pg_depend.objid = pg_rewrite.oid
JOIN pg_class as dependent_view ON pg_rewrite.ev_class = dependent_view.oid
JOIN pg_class as source_table ON pg_depend.refobjid = source_table.oid
JOIN pg_attribute ON pg_depend.refobjid = pg_attribute.attrelid
AND pg_depend.refobjsubid = pg_attribute.attnum
JOIN pg_namespace dependent_ns ON dependent_ns.oid = dependent_view.relnamespace
JOIN pg_namespace source_ns ON source_ns.oid = source_table.relnamespace
WHERE 1=1
-- AND source_ns.nspname = 'public'
AND source_table.relname like 'test_col_drp%'
AND pg_attribute.attnum > 0
AND pg_attribute.attname = 'col3'
)
select concat('alter table ', source_table, ' drop column ' , column_name, ' cascade;' ) as sql_command from query_result where id = 1
union all
select concat('create or replace view ', dependent_view, ' as select * from ', source_table, ';') as sql_command from query_result
Then, the output will be:
alter table test_col_drp drop column col3 cascade;
create or replace view test_col_drp_vw1 as select * from test_col_drp;
create or replace view test_col_drp_vw2 as select * from test_col_drp_vw1;

Drop constraint returned by select query in PostgreSQL

I'm writing a migration script to drop a constraint that has different names in different environments
Drop this constraint:
ALTER TABLE ONLY custom_data
ADD CONSTRAINT fk_rails_d86d725d64
FOREIGN KEY (custom_id) REFERENCES customs(id);
I'd like to do something like this: (but it doesn't work)
alter table custom_data
drop constraint (
SELECT CONSTRAINT_NAME
FROM INFORMATION_SCHEMA.KEY_COLUMN_USAGE
WHERE TABLE_NAME = 'custom_data'
AND COLUMN_NAME = 'custom_id')
Is there another way to rephrase above so it might work? Or could someone help me understand why the above doesn't work?
UPDATE
Also trying to use do but its not working either. The constraint still exists when I check.
do $$
declare c_name text;
begin
select constraint_name into c_name
from information_schema.key_column_usage
where table_name = 'custom_data' and
column_name = 'custom_id';
execute format ('alter table custom_data drop constraint %I', c_name);
end;
$$;
If running the select statement,
SELECT CONSTRAINT_NAME
FROM INFORMATION_SCHEMA.KEY_COLUMN_USAGE
WHERE TABLE_NAME = 'custom_data'
AND COLUMN_NAME = 'custom_id'
Sometimes the result is,
| constraint_name
_|____________________
1| fk_rails_d86d725d64
But sometimes the result is,
| constraint_name
_|____________________
1|
When running the big query to get the constraint and remove it,
Sometimes the result is,
Empty query string
But sometimes the result is,
Name | Value
_____________|___________
Query | do
Updated Rows | 0
Finish time | Tue Mar 21...
Its starting to seem like a bad whitespace issue to me now...
Could this also be impacted by the column already having an index as well?
CREATE INDEX index_custom_data_on_custom_id ON custom_data USING btree (custom_id);
Solution:
Change:
select constraint_name
from information_schema.key_column_usage
where table_name = 'custom_data' and
column_name = 'custom_id';
To:
select constraint_name
from information_schema.key_column_usage
where table_name = 'custom_data' and column_name = 'custom_id';
I guess it was a whitespace issue. Appreciated all the help in the comments.

Why is pg_table_def table returning tablenames containing the text "_$mig"

I am using pg_table_def to work out the primary keys associated to a given table, example below:
SELECT pg_table_def.tablename,
pg_table_def.column
FROM pg_table_def
WHERE schemaname = 'myschema'
AND tablename LIKE '%mytable%'
AND tablename LIKE '%_pkey%';
Example output from the above query:
tablename column
mytable_$mig_pkey id
This is correctly identifying the primary keys, but in some cases the format of the tablename returned has the text _$mig in it, for example: mytable_$mig_pkey.
I use the tablename in a later part of the code so currently have to remove this text. My questions are:
Why for some tables is the tablename formatted like this with _$mig?
Are there other strings that could appear between tablename and _pkey that should be taken into consideration?
Or is there a better way to identify the primary keys associated to a
table?
I've so far tried:
Checking the AWS documentation it recommends to check the search_path, so I've done this and made sure the schema is referenced in the where clause.
Checked that mytable_$mig doesn't exist / isn't available.
Other googling hasn't got me any further...
Update
Based on the comments below, running the below query:
select tablename, "column", type, encoding, distkey, sortkey, "notnull"
from pg_table_def
where schemaname = 'myschema' AND tablename LIKE '%mytable%';
Returns:
tablename column type encoding distkey sortkey notnull
mytable id integer none true 1 true
mytable desc character varying(50) lzo false 0 false
mytable_$mig_pkey id integer none true 1 false
Update:
So it looks like you have your actual table and one that was probably created accidentally. If you do select count(*) from mytable and select count(*) from mytable_$mig_pkey;, hopefully mytable has all your data and the other one is
empty. If so you can clean it up with drop table mytable_$mig_pkey.
I see you have the id column as the distkey which is Redshift's version of a primary key. You may also be trying to define constraints, which Redshift will allow you to do, but they are not enforced.
You can view the defined table constraints for a table like so:
select * from information_schema.table_constraints
where table_name='mytable';
On one of my tables gives a result like:
constraint_catalog | constraint_schema | constraint_name | table_catalog | table_schema | table_name | constraint_type | is_deferrable | initially_deferred
--------------------+-------------------+-----------------+---------------+--------------+------------+-----------------+---------------+--------------------
mydb | myschema | mytable_pkey | mydb | myschema | mytable | PRIMARY KEY | NO | NO
(1 row)
My current guess is that you attempted to define constraints on your table and accidentally created a second table at some point, which is why the other table has _pkey in its name.
I use a query like this myself:
select tablename, "column", type, encoding, distkey, sortkey, "notnull"
from pg_table_def
where schemaname = 'myschema' AND tablename LIKE '%mytable%';
Running something more general like that might help you figure out what's going on.
The \d I referenced in the comments is a way to list all the tables in the database that is a convenience function built into the psql command line app. The query it runs to do that is this:
SELECT n.nspname as "Schema",
c.relname as "Name",
CASE c.relkind WHEN 'r' THEN 'table' WHEN 'v' THEN 'view' WHEN 'm' THEN 'materialized view' WHEN 'i' THEN 'index' WHEN 'S' THEN 'sequence' WHEN 's' THEN 'special' WHEN 'f' THEN 'foreign table' END as "Type",
pg_catalog.pg_get_userbyid(c.relowner) as "Owner"
FROM pg_catalog.pg_class c
LEFT JOIN pg_catalog.pg_namespace n ON n.oid = c.relnamespace
WHERE c.relkind IN ('r','v','m','S','f','')
AND n.nspname <> 'pg_catalog'
AND n.nspname <> 'information_schema'
AND n.nspname !~ '^pg_toast'
AND pg_catalog.pg_table_is_visible(c.oid)
ORDER BY 1,2;
Running that might help.

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
...