PostgreSQL: Drop column and recreate dependent views - postgresql

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;

Related

when data in table is empty, show a record in a custom column

I have a view as below in PostgresSQL where if view returns no data, i have to show the column "view_lastmodifieddate" to be populated and every other column/row as empty. Again, only when the table has no data
CREATE OR REPLACE VIEW test AS
Select Column 1,
Column 2,
Column 3,
'2020-08-19 12:01:14' AS view_lastmodifieddate
From Table_1
You could use a union here:
WITH cte AS (
SELECT Col1, Col2, Col3, Col4, COUNT(*) FILTER (WHERE source = 1) OVER () AS cnt
FROM
(
SELECT Col1, Col2, Col3, Col4, 1 AS source FROM Table_1
UNION ALL
SELECT NULL, NULL, NULL, '2020-08-19 12:01:14'::timestamp, 2
) t
)
SELECT Col1, Col2, Col3, Col4
FROM cte
WHERE (cnt > 0 AND source = 1) OR (cnt = 0 AND source = 2);
If you really wanted this as a view, you could inline the CTE I provided above into the lower select query, and instead define that select as a view.
I would use a left join to accomplish this.
CREATE OR REPLACE VIEW test AS
select t.column1, t.column2, t.column3,
coalesce(t.view_lastmodifieddate, f.fixed_date) as view_lastmodifieddateb
from (values ('2020-08-19 12:01:14'::timestamp)) as f(fixed_date)
left join table_1 t
on true;

Postgres-11 : Alter Table dynamically

I am trying to alter table based on another table dynamically.
Below is the piece of code i wrote in postgresql stored procedure.
But running out into some syntax errors.
Please help me here.
I just started working in postgresql and i am from sql server background. Like how we do in sql server print stmts do debug dynamic queries inside procedures; do we have any link to refer please share that as well. It would help me.
DROP TABLE IF EXISTS temp_table;
CREATE TEMP TABLE temp_table AS
with cte as
(
select column_name,data_type,character_maximum_length
from information_schema."columns" c
where table_name = 'customer_new' and table_schema = 'public'
and column_default is null
)
,cte1 as
(
select column_name,data_type,character_maximum_length
from information_schema."columns" c
where table_name = 'customer_old' and table_schema = 'public'
and column_default is null
)
select cte.column_name,
case when cte.character_maximum_length is not null then cte.data_type||'('||cte.character_maximum_length||')' else cte.data_type end as data_type
from cte
left join cte1 on cte.column_name = cte1.column_name
where cte1.column_name is null;
for v_column_name,v_data_type in SELECT column_name,data_type FROM temp_table
loop
execute format ('alter table %s add column %s %s ;', v_dump_table_name, v_column_name, v_data_type);
end loop;
DROP TABLE IF EXISTS temp_table;
Thanks in advance.
DROP TABLE IF EXISTS temp_table;
CREATE TEMP TABLE temp_table AS
with cte as
(
select column_name,data_type,character_maximum_length
from information_schema."columns" c
where table_name = 'customer_new' and table_schema = 'public'
and column_default is null
)
,cte1 as
(
select column_name,data_type,character_maximum_length
from information_schema."columns" c
where table_name = 'customer_old' and table_schema = 'public'
and column_default is null
)
select 'alter table '||v_dump_table_name||' add column '||cte2.column_name||' '||data_type
as col
from cte2;
for v_column in SELECT col FROM temp_table
loop
execute format ('%s ;', v_column);
end loop;
DROP TABLE IF EXISTS temp_table;

amazon redshift utility - view v_generate_tbl_ddl not returning primary key constraint in ddl after table has been populated

I'm using the amazon redshift utility v_generate_tbl_ddl to generate a table ddl, but have found that after my table has been populated the primary key constraint doesn't show (example below)
Structure table creation:
DROP TABLE IF EXISTS temp_table;
CREATE TABLE temp_table
(
id INTEGER NOT NULL,
text VARCHAR,
PRIMARY KEY (id)
)
DISTSTYLE ALL SORTKEY (id);
Checking the ddl after the table has been created shows the primary key constraint is present:
SELECT *
FROM admin.v_generate_tbl_ddl
WHERE tablename = 'temp_table'
AND schemaname = 'myschema';
Inserting some data:
COPY temp_table
FROM 's3://s3_bucket_location/manifest_file_temp_table.json' CREDENTIALS 'aws_access_key_id=...;aws_secret_access_key=...' DELIMITER AS '|' gzip manifest
Checking again the ddl and now the primary key constraint isn't there
SELECT *
FROM admin.v_generate_tbl_ddl
WHERE tablename = 'temp_table'
AND schemaname = 'myschema';
I'm sure the primary key is still there as I've doubled checked using:
SELECT pg_table_def.tablename,
pg_table_def.column
FROM pg_table_def
WHERE schemaname = 'myschema'
AND tablename = 'temp_table_pkey';
Digging into the sql of v_generate_tbl_ddl it is this section that isn't returning rows after the table has been populated, but I can't figure out why this stops returning rows? Any help here would be appreciated
SELECT n.nspname AS schemaname,
c.relname AS tablename,
200000000 + CAST(con.oid AS INT) AS seq,
('\t,' + pg_get_constraintdef(con.oid))::CHARACTER VARYING (500) AS ddl
FROM pg_constraint AS con
INNER JOIN pg_class AS c
ON c.relnamespace = con.connamespace
AND c.relfilenode = con.conrelid
INNER JOIN pg_namespace AS n ON n.oid = c.relnamespace
WHERE c.relkind = 'r'
AND pg_get_constraintdef (con.oid) NOT LIKE 'FOREIGN KEY%'
AND c.relname = 'temp_table'
ORDER BY seq

Issue in my Dynamic Query

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;

TSQL Getting the ident_current of a view this uses joins

Using the following queries, I am trying to understand why I am able to get the ident_current on one view, but not the other.
Here is some sample data:
create table temptable1 (id int identity(1,1), name varchar(100), [type] int)
insert into temptable1 values
( 'apple', 1),
( 'banana', 1),
( 'cake', 3)
create table temptable2 (id int identity(1,1), name varchar(100))
insert into temptable2 values
( 'fruit'),
( 'vegetable'),
( 'pastry')
exec ('
create view dbo.identcurrentworks
as
select
t1.id as t1id
,t1.name as t1name
,t1.type as t1type
from temptable1 t1
')
--drop view dbo.identcurrentworks
exec ('
create view dbo.identcurrentdoesnotwork
as
select
t1.id as t1id,
t1.name as t1name,
t1.type,
t2.id as t2id,
t2.name as t2name
from temptable1 t1
join temptable2 t2 on t1.type=t2.id
')
--drop view dbo.identcurrentdoesnotwork
select * from dbo.identcurrentworks
select IDENT_CURRENT('dbo.temptable1')
select IDENT_CURRENT('dbo.identcurrentworks')
select * from dbo.identcurrentdoesnotwork
select IDENT_CURRENT('dbo.temptable2')
select IDENT_CURRENT('dbo.identcurrentdoesnotwork')
--drop table temptable1
--drop table temptable2
I am uncertain as to why I can get the ident_current on the view dbo.identcurrentworks but not on the other. Any ideas?
#Pondlife is right - the view identcurrentdoesnotwork has no identity column defined because there are two identity columns in the select statement. You can verify this by running:
sp_help identcurrentdoesnotwork
Note that as the others have pointed out, for most situations, one should use SCOPE_IDENTITY instead of IDENTITY_CURRENT.
For more on IDENT_CURRENT, click here, and for more on ##IDENTITY vs IDENT_CURRENT vs SCOPE_IDENTITY, click here .