insert and update a table using cursor - sql

I'm trying to insert records to table
input from information_schema :
select table_schema,table_name,table_type
from information_schema.tables
where table_schema = 'MYSCHEMA';
expected output:
insert into new table along with DDL of table_name
to get DDL: select get_ddl('table','INVOICING')
Can you help me?
create or replace procedure proc_getddl
is
v_tableschema varchar(30);
v_tablename varchar(30);
v_tabletype varchar(30);
v_getddl varchar(110);
cursor getddl is
select table_schema,table_name,table_type,get_ddl('table','INVOICING')
from information_schema.tables
where table_schema = 'MYSCHEMA';
begin
open getddl;
LOOP
fetch getddl into v_tableschema,v_tablename,v_tabletype,v_getddl;
EXIT WHEN getddl%NOTFOUND;
INSERT INTO backup_table
values (v_tableschema,v_tablename,v_tabletype,v_getddl);
END LOOP;
close getddl;
end proc_getddl;
I can use this but I want it to execute for all tables in information schema

Try something like
create table backup_table as
select table_schema,table_name,table_type,get_ddl('table','INVOICING')
from information_schema.tables
where table_schema = 'MYSCHEMA';
According to this https://sparkbyexamples.com/snowflake/snowflake-create-table-as-select/

Related

dynamic SQL ERROR: column "age" does not exist

postgres 12
I am trying to loop through a table which has schema , table_names and columns
I want to do various things like finding nulls ,row count etc. I failed at the first hurdle trying to update the col records.
table i am using
CREATE TABLE test.table_study (
table_schema text,
table_name text,
column_name text,
records int,
No_Nulls int,
No_Blanks int,
per_pop int
);
I populate the table with some schema names ,tables and columns from information_schema.columns
insert into test.table_study select table_schema, table_name, column_name
from information_schema.columns
where table_schema like '%white'
order by table_schema, table_name, ordinal_position;
I want to populate the rest with a function
function :-
CREATE OR REPLACE PROCEDURE test.insert_data_population()
as $$
declare s record;
declare t record;
declare c record;
BEGIN
FOR s IN SELECT distinct table_schema FROM test.table_study
LOOP
FOR t IN SELECT distinct table_name FROM test.table_study where table_schema = s.table_schema
loop
FOR c IN SELECT column_name FROM test.table_study where table_name = t.table_name
LOOP
execute 'update test.table_study set records = (select count(*) from ' || s.table_schema || '.' || t.table_name || ') where table_study.table_name = '|| t.table_name ||';';
END LOOP;
END LOOP;
END LOOP;
END;
$$
LANGUAGE plpgsql;
I get this error SQL Error [42703]: ERROR: column "age" does not exist. the table age does exist.
when I take out the where clause
execute 'update referralunion.testinsert ti set records = (select count(*) from ' || s.table_schema || '.' || t.table_name || ') ;';
it works, I just cant figure out whats wrong?
Your procedure is structured entirely wrong. What it results in is an attempt to get every column name for every table name in every schema. I would guess results in your column does not exist error. Further is shows procedural thinking. SQL requires think in terms of sets. Below I use basically your query to demonstrate then a revised version which uses a single loop.
-- setup (dropping schema references)
create table table_study (
table_schema text,
table_name text,
column_name text,
records int,
no_nulls int,
no_blanks int,
per_pop int
);
insert into table_study(table_schema, table_name, column_name)
values ('s1','t1','age')
, ('s2','t1','xyz');
-- procedure replacing EXECUTE with Raise Notice.
create or replace procedure insert_data_population()
as $$
declare
s record;
t record;
c record;
line int = 0;
begin
for s in select distinct table_schema from table_study
loop
for t in select distinct table_name from table_study where table_schema = s.table_schema
loop
for c in select column_name from table_study where table_name = t.table_name
loop
line = line+1;
raise notice '%: update table_study set records = (select count(*) from %.% where table_study.table_name = %;'
, line, s.table_schema, t.table_name, c.column_name;
end loop;
end loop;
end loop;
end;
$$
language plpgsql;
Run procedure
do $$
begin
call insert_data_population();
end;
$$;
RESULTS
1: update table_study set records = (select count(*) from s2.t1 where table_study.table_name = age; 2: update table_study set records = (select count(*) from s2.t1 where table_study.table_name = xyz; 3: update table_study set records = (select count(*) from s1.t1 where table_study.table_name = age; 4: update table_study set records = (select count(*) from s1.t1 where table_study.table_name = xyz;
Notice lines 2 and 3. Each references a column name that does not exist in the table. This results from the FOR structure with the same table name in different schema.
Revision for Single Select statement with Single For loop.
create or replace
procedure insert_data_population()
language plpgsql
as $$
declare
s record;
line int = 0;
begin
for s in select distinct table_schema, table_name, column_name from table_study
loop
line = line+1;
raise notice '%: update table_study set records = (select count(*) from %.% where table_study.table_name = %;'
, line, s.table_schema, s.table_name, s.column_name;
end loop;
end;
$$;
do $$
begin
call insert_data_population();
end;
$$;
RESULTS
1: update table_study set records = (select count(*) from s2.t1 where table_study.table_name = xyz;
2: update table_study set records = (select count(*) from s1.t1 where table_study.table_name = age;
Note: In Postgres DECLARE begins a block. It is not necessary to declared each variable. I would actually consider it bad practice. In theory it could require an end for each declare as each could be considered a nested block. Fortunately Postgres does not require this.

how to update all tables with a particular column name

I am trying to update all tables starting with string like 'agg%' and column_name ='%userid%'...
But i dont see any such examples online even though i was able to find option to select all tables with a particular column name and table name I need to do the same to update those tables something like this :
update TABLE_NAME set COLUMN_NAME='rajeev' WHERE COLUMN_NAME LIKE '%userid%'
and TABLE_NAME LIKE 'agg%'
FROM INFORMATION_SCHEMA.COLUMNS;
Help would be appreciated.
Thanks.
To get the update query for your condition
select
'update '||c.table_name||' set '||c.COLUMN_NAME||' = ''rajeev'';'
as my_update_query
from
(select
table_name,COLUMN_NAME
from INFORMATION_SCHEMA.COLUMNS
where table_name LIKE 'agg%' and COLUMN_NAME LIKE '%userid%') c
To execute
do $$
declare
arow record;
begin
for arow in
select
'update '||c.table_name||' set '||c.COLUMN_NAME||' = ''rajeev'';'
as my_update_query
from
(select
table_name,COLUMN_NAME
from INFORMATION_SCHEMA.COLUMNS
where table_name LIKE 'agg%' and COLUMN_NAME LIKE '%userid%') c
loop
execute arow.my_update_query;
end loop;
end;
$$;

Row count column count in all tables in Sybase database

I have a database name ATs . In this database 150 tables. I want to create a statement that return the row count and column count all tables on the database .
I have created a store procedure For SQL SERVER 2008 but i don't know how to write this script for Sybase.
Sybase ASA has a bunch of system tables providing you with information about the structure of your database. The two tables that are of interest for you are SYSTABLE (all tables) and SYSCOLUMN (all columns).
I tried this quick and dirty stored procedure that works for me (on the rather aged ASA version 8!). It creates a temporary table and a cursor to iterate over all tables. For every table the table name, number of columns and number of rows are inserted into the temp table and finally returned.
(Hint: the tablefilter allows to return only a subset of the whole database, if you have many tables.)
CREATE PROCEDURE Usr_TableStats(in par_tablefilter char(100))
RESULT (tablename varchar(255), number_of_cols int, number_of_rows int)
BEGIN
declare err_notfound exception for sqlstate value '02000';
declare #table_id integer;
declare #tablename varchar(100);
declare #cols integer;
declare #sql varchar(300);
declare tables no scroll cursor for select table_id, table_name from sys.systable where table_type = 'BASE' and table_name like par_tablefilter || '%' order by table_name;
create table #tablestats (
tablename varchar(100) not null,
number_of_cols int not null default 0,
number_of_rows int not null default 0
);
open tables;
LoopTables: loop
fetch next tables into #table_id, #tablename;
if sqlstate = err_notfound then
leave LoopTables
else
SELECT COUNT(column_id) INTO #cols FROM SYSCOLUMN WHERE table_id = #table_id;
set #sql= 'INSERT INTO #tablestats SELECT ''' || #tablename || ''', ' || #cols || ', COUNT(*) FROM ' || #tablename || ';';
EXECUTE IMMEDIATE WITH QUOTES #sql;
end if
end loop LoopTables;
close tables;
SELECT tablename, number_of_cols, number_of_rows FROM #tablestats;
END
Call it in iSQL like this:
CALL Usr_TableStats('%'); -- all tables
CALL Usr_TableStats('ADDRESS%'); -- only tables starting with ADDRESS
sys.systable and sys.syscolumn should provide you with the information:
Select st.table_name,
st.count as row_count,
col_count = (SELECT count(*) FROM sys.syscolumn where table_id = st.table_id)
from SYS.SYSTABLE st where st.creator <> 0 and st.count > 0
order by st.table_name

Catching an exception while altering a table in Oracle

I'm trying to write a command in Oracle that will wither ADD or MODIFY a column depending on whether or not it already exists. Basically something like:
BEGIN
ALTER TABLE MY_TABLE ADD ( COL_NAME VARCHAR2(100 );
EXCEPTION WHEN OTHERS THEN
ALTER TABLE MY_TABLE MODIFY ( COL_NAME VARCHAR2(100) );
END;
However, Oracle complains about having the ALTER command inside of BEGIN. Is there a way to achieve this using a single SQL command in Oracle?
Thanks!
In order to put DDL in a PL/SQL block, you would need to use dynamic SQL.
Personally, I'd check whether the column exists first and then issue the DDL. Something like
DECLARE
l_cnt INTEGER;
BEGIN
SELECT COUNT(*)
INTO l_cnt
FROM dba_tab_cols
WHERE table_name = 'MY_TABLE'
AND owner = <<owner of table>>
AND column_name = 'COL_NAME';
IF( l_cnt = 0 )
THEN
EXECUTE IMMEDIATE 'ALTER TABLE my_table ADD( col_name VARCHAR2(100) )';
ELSE
EXECUTE IMMEDIATE 'ALTER TABLE my_table MODIFY( col_name VARCHAR2(100) )';
END IF;
END;
If you don't have access to DBA_TAB_COLS, you could also use ALL_TAB_COLS or USER_TAB_COLS depending on what schema the table resides in and what privileges you have on the table.
I found a solution based on this post.
DECLARE v_column_exists number := 0;
BEGIN
SELECT COUNT(*) INTO v_column_exists
FROM ALL_TAB_COLUMNS
WHERE TABLE_NAME = 'MY_TABLE'
AND COLUMN_NAME = 'COL_NAME';
IF (v_column_exists = 0) THEN
EXECUTE IMMEDIATE 'ALTER TABLE MY_TABLE ADD ( COL_NAME VARCHAR2(200) )';
ELSE
EXECUTE IMMEDIATE 'ALTER TABLE MY_TABLE MODIFY ( COL_NAME VARCHAR2(200) )';
END IF;
END;

MySQL Backup Table if it Exists

I am trying to write a script that will copy all the data in table a to table b if table a exists. Table b is the exact same structure as table a would be if it exists, though it may not. I am able to copy using the following statement: INSERT INTO 'B' SELECT * FROM 'A', but I don't know where to use IF EXISTS, or if I even can to determine if I an perform the insertion. I am trying to do this in SQL only as it will be run through as a .sql script from the command line.
MySQL only:
DROP PROCEDURE IF EXISTS myupdate;
DELIMITER //
CREATE PROCEDURE myupdate ()
BEGIN
DECLARE found VARCHAR(64);
SET found = (SELECT TABLE_NAME FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_SCHEMA = Database() AND TABLE_NAME = 'A');
IF found = 'types' THEN
INSERT INTO B SELECT * FROM A;
SELECT 'A into B';
ELSE
SELECT 'A not found';
END IF;
END;//
DELIMITER ;
CALL myupdate();
DROP PROCEDURE myupdate;
Expand to you're liking comparing the column definition in INFORMATION_SCHEMA.COLUMNS for A & B if you need finer control.
I have accepted Wrikken's answer but am using this as my final code. I need to reuse the procedure he provided for multiple tables, so I modified it slightly. It makes the assumption that the backup table has already been created.
DROP PROCEDURE IF EXISTS tableUpdate;
DELIMITER //
CREATE PROCEDURE tableUpdate(name VARCHAR(32))
BEGIN
DECLARE cnt tinyint(1);
DECLARE btable VARCHAR(36);
SET btable = CONCAT(name,'BAK');
SET cnt = (SELECT COUNT(TABLE_NAME) FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_SCHEMA = 'TAA' AND TABLE_NAME = name);
IF cnt > 0 THEN
SET #q:= CONCAT('INSERT INTO ',CONCAT(btable,CONCAT(' SELECT * FROM ',name)));
PREPARE stmt FROM #q;
EXECUTE stmt;
COMMIT;
ELSE
SELECT 'No update necessary.';
END IF;
END;//
DELIMITER ;
CALL tableUpdate('A');
DROP PROCEDURE tableUpdate;
You can do so by performing the following:
select count(*) from my_tables where table_name='b';
If count>0 then
update b...;
else
create table b;
insert into my_tables(table_name) values('b');
insert into b...;
end if;