Dynamically renaming of column names with column values present in some other table in oracle - sql

I am trying to solve a problem where I have 2 tables in Oracle:
Table 1
id name
101 xyz
102 abc
103 def
Table 2
columnname columndesc
id identifier
name customer name
I want to rename the column name of Table1 with the values present in Table2
Expected output is:
identifier customer name
101 xyz
102 abc
103 def

One option you could try is you should use a Cursor to iterate through each row of Table1 and for each of these rows execute the alter table.
Another option is to also use a cursor to iterate through Table rows and instead build one Alter Table statement, which in turn can be run with EXEC
Useful links:
Alter Table
List item
Execute command

For such dynamic renaming you have to use execute immediate to achieve it,
Here is the sample code using a normal for loop,
begin
for i in (select columnname,columndesc from table2) loop
begin
execute immediate 'alter table table1 rename column '||i.columnname ||' to '||i.columndesc;
exception
when others then
dbms_output.put_line('Renaming failed for column '''|| i.columnname ||''' and columndesc '''||i.columndesc||'''');
continue;
end;
end loop;
end;
/
The code is self explanatory, however I have listed some points to be taken care which are instantly coming to mind.
I hope the the table1's columns you are trying to rename are exactly same as value of columnname in table2
During the rename as you see I have put the statements in begin end and using exception we just skip the one which will fail.
Failure reason could be anything such as,
. the column name you are trying to rename doesn't exists
. the column name value from columndesc exceeds 30/128 char (version < oracle 12.2 and version > oracle 12.2 its 128 characters ) which is the limit in oracle for object names
I have hard coded the table table1 as only talble to rename in this example but again you have got idea now where you can even make the table as dynamic also if you want.
At the end bottom line is to use execute immediate for your primary purpose but you also need to consider all the failure cases as the compilation and execution of the actual statements will happen during run time.
EDIT:
Do not use space in columndesc in table2 as customr name rather use - like customer_name which is standard naming for oracle.

Related

SQL command not ended properly at pkg_test

I have to write a stored procedure that starts copying the data from a table 'company' into a staging table 'company_stg' if no records for that date are present in it.
I have the following code :
CREATE OR REPLACE
PACKAGE BODY PKG_TEST AS
PROCEDURE SP_BILLING AS
BEGIN
EXECUTE IMMEDIATE 'SELECT * FROM COMPANY INTO COMPANY_STG
WHERE NOT EXISTS (SELECT * FROM COMPANY_STG WHERE AS_OF_DATE = "2023-02-08")';
END;
END PKG_TEST;
I AM GETTING THE ERROR "SQL COMMAND NOT PROPERLY ENDED"
company * company_stg have as_of_date as a column. rest all are same.
please help me with this
I have also tried
if not exists (SELECT * FROM COMPANY_STG WHERE AS_OF_DATE = "2023-02-08")
then
select from company into company_stg
So many things look bad in that piece of code...
First, why use dynamic SQL execute immediate? It's best to avoid dynamic SQL as much as possible because it leads to runtime errors and requires pretty much instrumentation so that it may be debugged. Generally you use dynamic SQL when you do not know beforehand the name of a table it will operate on, which is not the case for you. You definitely know you have to work with tables COMPANY and COMPANY_STG. Is it not so?
Then, it doesn't look like you have read the manual to see an insert select.
When you insert into a table, it's best to give the list of columns into which you actually insert data. If one alters that table and adds one or more than one column, the insert which does not have the list of columns will crash.
Thus, to insert into COMPANY_STG data from COMPANY, the SQL should look like below:
insert into company_stg(
... ---- here should be the list of columns you insert data into
)
select
... --- here should the source columns you are willing to insert
from company c
where not exists (
select 1
from company_stg cs
where cs.as_of_date= --- what is the condition??? I did not understand
)
;
You have not given the structures for those tables, so that I can't give you the columns to select and to insert into. Nor did I really understand what the condition for inserting data should be.
SELECT does not perform a copy and SELECT * FROM COMPANY INTO COMPANY_STG is not valid syntax. You want to use an INSERT statement to do that (and check if there is any row first):
CREATE OR REPLACE PACKAGE BODY PKG_TEST AS
PROCEDURE SP_BILLING
AS
BEGIN
DECLARE
v_staged_count NUMBER;
BEGIN
SELECT 1
INTO v_staged_count
FROM COMPANY_STG
WHERE AS_OF_DATE = DATE '2023-02-08'
FETCH FIRST ROW ONLY; -- We don't care how many rows so stop after finding
-- the first one.
-- Stop as rows have been found.
RETURN;
EXCEPTION
WHEN NO_DATA_FOUND THEN
-- Continue
NULL;
END;
INSERT INTO company_stg
SELECT *
FROM COMPANY;
END;
END PKG_TEST;
/
fiddle

Oracle SQL combine columns from one table

i am using oracle sql developer and want to build a trigger to insert values into a table column.
My table is:
column1(num) | column2(num) | column3(var)
1 5
6 4
7 3
I want to combine the first two columns, so in the end column3 should look like this:
column3(var)
1_5
6_4
7_3
My Idea was:
create or replace TRIGGER "Database"."TRIGGER"
BEFORE INSERT OR UPDATE ON "Database"."TABLE"
FOR EACH ROW
BEGIN
SELECT column1 || column2
INTO :NEW.column3
FROM TRIGGER;
END;
But column3 is still empty, can anybody tell me what i am doing wrong?
thanks in advance
Rather than using a trigger, you can preferably add a virtual column after dropping the existing one such as
SQL> ALTER TABLE t DROP COLUMN col3;
SQL> ALTER TABLE t
ADD (
col3 AS (col1||'_'||col2)
);
which always will depend on those two columns, and any DML is not allowed, already not needed, it's good for displaying purposes with no interfering human factor.
Demo
BEGIN
:NEW.column3 :=column1 || column2;
END;
Calling a trigger name "Trigger" is a bad idea.

Executing a PostgreSQL query with an EXCEPTION results in two different ERROR messages

I have an PostgreSQL query that includes a transaction and an exception if a column is duplicated:
BEGIN;
ALTER TABLE "public"."cars"
ADD COLUMN "top_speed" text;
EXCEPTION WHEN duplicate_column THEN NOTHING;
ROLLBACK;
In this query I am trying to add a column that already exists (playing a little bit with exceptions) and if it does then the query shall just ignore it. At the moment I am not really sure if the exception-code I am using is the right (couldn't find a site where they are described; only found this)
My Problem is if I execute this query I get the error-message:
ERROR: column "top_speed" of relation "cars" already exists
And if I execute it a second time the error-message changes to:
ERROR: current transaction is aborted, commands ignored until end of transaction block
Try an anonymous code block. As Laurenz mentioned, you were mixing PL/pgSQL and SQL commands.
Sample table
CREATE TABLE t (f1 TEXT);
Anonymous code block
DO $$
BEGIN
IF (SELECT count(column_name) FROM information_schema.columns
WHERE table_schema = 'public' AND
table_name = 't' AND
column_name = 'f2') = 0 THEN
ALTER TABLE public.t ADD COLUMN "f2" text;
END IF;
END$$;
After execution you have your new column. If the column already exists, it will do nothing.
SELECT * FROM t;
f1 | f2
----+----
0 Zeilen
In PostgreSQL 9.6+ you can use IF NOT EXISTS to check if a given column already exists in the table before creating it:
ALTER TABLE t ADD COLUMN IF NOT EXISTS f2 TEXT;
Code at db<>fiddle

Delete all data from a table after selecting all data from the same table

All i want is to select all rows from a table and once it is selected and displayed, the data residing in table must get completely deleted. The main concern is that this must be done using sql only and not plsql. Is there a way we can do this inside a package and call that package in a select statement? Please enlighten me here.
Dummy Table is as follows:
ID NAME SALARY DEPT
==================================
1 Sam 50000 HR
2 Max 45000 SALES
3 Lex 51000 HR
4 Nate 66000 DEV
Any help would be greatly appreciated.
select * from Table_Name;
Delete from Table_Name
To select the data from a SQL query try using a pipelined function.
The function can define a cursor for the data you want (or all the data in the table), loop through the cursor piping each row as it goes.
When the cursor loop ends, i.e. all data has been consumed by your query, the function can perform a TRUNCATE table.
To select from the function use the following syntax;
SELECT *
FROM TABLE(my_function)
See the following Oracle documentation for information pipelined functions - https://docs.oracle.com/cd/B28359_01/appdev.111/b28425/pipe_paral_tbl.htm
This cannot be done inside a package, because " this must be done using sql only and not plsql". A package is PL/SQL.
However it is very simple. You want two things: select the table data and delete it. Two things, two commands.
select * from mytable;
truncate mytable;
(You could replace truncate mytable; with delete from mytable;, but this is slower and needs to be followed by commit; to confirm the deletion and end the transaction.)
Without pl/sql it's not possible.
Using pl/sql you can create a function which will populate a row, and then delete
Here is example :
drop table tempdate;
create table tempdate as
select '1' id from dual
UNION
select '2' id from dual
CREATE TYPE t_tf_row AS OBJECT (
id NUMBER
);
CREATE TYPE t_tf_tab IS TABLE OF t_tf_row;
CREATE OR REPLACE FUNCTION get_tab_tf RETURN t_tf_tab PIPELINED AS
PRAGMA AUTONOMOUS_TRANSACTION;
BEGIN
FOR rec in (select * from tempdate) LOOP
PIPE ROW(t_tf_row(rec.id));
END LOOP;
delete from tempdate ; commit;
END;
select * from table(get_tab_tf) -- it will populate and then delete
select * from tempdate --you can check here result of deleting
you can use below query
select * from Table_demo delete from Table_demo
The feature you seek is SERIALIZABLE ISOLATION LEVEL. This feature enables repeatable reads, which in particular guarantee that both SELECTand DELETEwill read and process the same identical data.
Example
Alter session set isolation_level=serializable;
select * from tempdate;
--- now insert from other session a new record
delete from tempdate ;
commit;
-- re-query the table old records are deleted, new recor preserved.

Normalize columns names in ORACLE 11g

I need remove the quotes from the names of the columns in many tables in my schema. there is any way to automate this process?, any function in oracle or some tool that allows me to change the names of the columns removing the quotes. I am using oracle 11g.
UPDATE
I'm sorry, I had to rephrase my question.
thanks in advance.
I assume here by "fields" you mean "column names".
Keep in mind that column names in Oracle are not case sensitive unless you put them in quotes when creating the table. It's generally not a good idea to use quotes around the column names when creating the table. In other words, if you create the table like this:
CREATE TABLE FOO (
colUMN1 varchar2(10),
CoLumn2 number(38)
)
Then you can still run select statements like this:
SELECT column1, column2 FROM FOO
You can also do this:
SELECT COLUMN1, COLUMN2 FROM FOO
Also note that if you run this query, you'll see that Oracle stored the column names as uppercase in the data dictionary:
SELECT * FROM ALL_TAB_COLUMNS WHERE TABLE_NAME = 'FOO'
So there's no need to rename these columns to all uppercase. The queries you write can use all uppercase column names (assuming the tables weren't created using quotes around the column names) and they'll work fine. It's generally a bad idea to try to force them to be case sensitive.
If you just want to get rid of all the case sensitive column names
SQL> create table foo ( "x" number );
Table created.
SQL> ed
Wrote file afiedt.buf
1 begin
2 for x in (select *
3 from user_tab_cols
4 where column_name != UPPER(column_name))
5 loop
6 execute immediate 'ALTER TABLE ' || x.table_name ||
7 ' RENAME column "' || x.column_name || '"' ||
8 ' TO ' || upper(x.column_name);
9 end loop;
10* end;
SQL> /
PL/SQL procedure successfully completed.
SQL> desc foo
Name Null? Type
----------------------------------------- -------- ----------------------------
X NUMBER