check if multiple records exist in table ORACLE PLSQL - oracle

Here I want to check if record exists and based on that I want perform actions.
My code is as below
FOR cell_configs IN (SELECT cc.cell_configuration_name,
cc.cell_configuration_value
from cell_configurations cc
where (cc.cell_configuration_name like height_cc or
cc.cell_configuration_name like width_cc) and
cc.cell_id=c_id)
LOOP
if cc.cell_configuration_name OR
cc.cell_configuration_value EXISTS
then
-- i want to update the table dbms_output.put_line(temp || ' does exist');
else
-- i want to insert records into the table dbms_output.put_line(temp || ' does not exist');
end if;
dbms_output.put_line(c_id || ' ' ||
cell_configs.cell_configuration_name || ' ' ||
cell_configs.cell_configuration_value );
END LOOP;
If there are no records found I can see that I will get empty string i.e ''. I cannot check if it is null or not.
Can anybody help me on this please?.
EDIT (info copied from comments):
I am looking for these 2 rows(height,width) cell_configuration_name like 'container.dealer-content.configs[1].width' or cell_configuration_name like 'container.dealer-content.configs[1].height' cell_configuration_value=flex-width-8 cell_configuration_value=flex-width-250
CELL_CONFIGURATIONS table below
CELL_CONFIGURATION_ID NUMBER(38,0) PK
CELL_ID NUMBER(38,0) FK
CELL_CONFIGURATION_NAME VARCHAR2(100 BYTE)
CELL_CONFIGURATION_VALUE VARCHAR2(4000 BYTE)
IS_LOCKED CHAR(1 BYTE)
MODIFIED_BY VARCHAR2(100 BYTE)
MODIFIED_DATE DATE
CREATED_BY VARCHAR2(100 BYTE)
CREATED_DATE
Sample Data as Below
CELL_ID CELL_CONFIGURATION_NAME CELL_CONFIGURATION_VALUE
37771286880 container.dealer-content.configs[1].height flex-height-2
37771286880 container.dealer-content.configs[1].width flex-width-8

Here is the beggining of a solution...
BEGIN
FOR rec IN
(SELECT cell_id -- assuming that cell_id will repeat for lines with width and height
FROM CELL_CONFIGURATIONS
WHERE CELL_CONFIGURATION_NAME LIKE height_cc
MINUS
SELECT cell_id
FROM CELL_CONFIGURATIONS
WHERE CELL_CONFIGURATION_NAME LIKE width_cc
)
LOOP
-- INSERT STATEMENT
END LOOP;
END;

Related

PL/SQL Records. Can i put in records few values?

I'm working in Apex Oracle PL/SQL and trying to understand how records work.
There is piece of code. I can't understand why i'm getting exception "no data found".
And can i put few rows in records?
create table testProducts
(
prod_id number not null,
group_id number (5) not null,
prod_name varchar2(50) not null,
constraint fk_group_id foreign key (group_id)
references testGroups(group_id)
)
declare
type mr is record (
prod_Id testProducts.prod_Id%type
);
obj_mr mr;
maxd number;
egin
select max(prod_Id) into maxd from testProducts;
for i in 10..maxd loop
select testProducts.prod_id into obj_mr from testProducts where
testProducts.prod_Id = i;
dbms_output.put_line(obj_mr.prod_id);
end loop;
end;
To resolve your immediate issues, you are getting a no data found error because you are starting looping at prod_id 10 and going up sequentially to the maximum prod_id that exists in the table. If you have any gaps in your IDs then you will get the error. You can resolve it with some error handling like this:
DECLARE
TYPE mr IS RECORD
(
prod_Id testProducts.prod_Id%TYPE,
GROUP_ID testProducts.GROUP_ID%TYPE,
prod_name testProducts.prod_name%TYPE
);
obj_mr mr;
maxd NUMBER;
BEGIN
SELECT MAX (prod_Id) INTO maxd FROM testProducts;
FOR i IN 10 .. NVL (maxd, 1)
LOOP
BEGIN
SELECT prod_id, GROUP_ID, prod_name
INTO obj_mr
FROM testProducts
WHERE prod_Id = i;
DBMS_OUTPUT.put_line (obj_mr.prod_id || '|' || obj_mr.GROUP_ID || '|' || obj_mr.prod_name);
EXCEPTION
WHEN NO_DATA_FOUND
THEN
DBMS_OUTPUT.put_line ('prod_id does not exist: ' || i);
END;
END LOOP;
END;
/
To answer your question about multiple rows, no a RECORD type can not have multiple rows, but a TABLE type can. If you define a TABLE type of your RECORD type, you can then select multiple rows in to that TABLE type. See the code below for an example of how to do that.
DECLARE
TYPE mr IS RECORD
(
prod_Id testProducts.prod_Id%TYPE,
GROUP_ID testProducts.GROUP_ID%TYPE,
prod_name testProducts.prod_name%TYPE
);
TYPE mr_t IS TABLE OF mr;
obj_mr_t mr_t;
BEGIN
SELECT prod_id, GROUP_ID, prod_name
BULK COLLECT INTO obj_mr_t
FROM testProducts
ORDER BY prod_id;
FOR i IN 1 .. obj_mr_t.COUNT
LOOP
DBMS_OUTPUT.put_line (
obj_mr_t (i).prod_id || '|' || obj_mr_t (i).GROUP_ID || '|' || obj_mr_t (i).prod_name);
END LOOP;
END;
/

Truncate partitions older than 2 months

How to truncate partitions with data older than 2 months?
For an example, i have below table/partition names:
select table_name, partition_name from all_tab_partitions where table_name='TABLENAME';
TABLENAME partitionname1_P30 30
TABLENAME partitionname2_P60 60
TABLENAME partitionname3_P90 90
TABLENAME partitionname4_P120 120
TABLENAME partitionname5_P150 150
TABLENAME partitionname6_P180 180
TABLENAME partitionname7_210 210
TABLENAME partitionname8_P240 240
TABLENAME partitionname9_P270 270
TABLENAME partitionname10_P300 300
TABLENAME partitionname11_P330 330
TABLENAME partitionname12_P360 360
Table is partitioned per month. If we're currently on September, how do I truncate partitions older than 2 months?
Expectation is that only records from Aug-Sep (partitionname8-9) will remain while the rest will be truncated.
CREATE TABLE dbo1.TABLENAME
( PARTITION_ID NUMBER(4, 0) NOT NULL,
TABLE_DATE DATE NOT NULL,
TABLE_TIMESTAMP NUMBER(19, 0) NOT NULL,
TABLE_BUNDLE_ID VARCHAR2(240 BYTE) NOT NULL,
TABLE_TYPE NUMBER(8, 0) NOT NULL,
TABLE_SEVERITY NUMBER(19, 0) NOT NULL,
TABLE_FACILITY NUMBER(19, 0) NOT NULL,
TABLE_HOST VARCHAR2(120 BYTE) NOT NULL,
TABLE_PROCESS VARCHAR2(240 BYTE) NOT NULL,
TABLE_SYSTEM VARCHAR2(240 BYTE) NOT NULL,
TABLE_SESSION_ID VARCHAR2(240 BYTE) NOT NULL,
TABLE_PRINCIPAL VARCHAR2(120 BYTE) NOT NULL,
OBJECT_ID VARCHAR2(120 BYTE),
OBJECT_TYPE VARCHAR2(2 BYTE),
CLIENT_HOST VARCHAR2(120 BYTE),
ACCESS_HOST VARCHAR2(120 BYTE),
SCOPE_ID VARCHAR2(120 BYTE),
STATUS NUMBER(19, 0),
OBJECT_HISTORY NUMBER(19, 0),
TABLE_DETAILS VARCHAR2(4000 BYTE)
)
PARTITION BY RANGE (PARTITION_ID)
(
PARTITION partitionname1_P30 VALUES LESS THAN (30)
,<repeat partition by 30s up to 360, total of 12 partitions>
You can do it like this:
DECLARE
CURSOR PartTables IS
SELECT TABLE_NAME, PARTITION_NAME, HIGH_VALUE
FROM USER_TAB_PARTITIONS
WHERE TABLE_NAME = 'TABLENAME';
highValue TIMESTAMP;
BEGIN
FOR aTab IN PartTables LOOP
EXECUTE IMMEDIATE 'BEGIN :ret := '||aTab.HIGH_VALUE||'; END;' USING OUT highValue;
IF highValue < ADD_MONTHS(SYSDATE, -2) THEN
EXECUTE IMMEDIATE 'ALTER TABLE TABLENAME TRUNCATE PARTITION '||aTab.PARTITION_NAME||' UPDATE INDEXES';
END IF;
END LOOP;
END;
This would work for a RANGE or INTERVAL based partitions, however in this case your requirement is rather useless because you would keep empty partitions for ever. Usually you drop old partitions, for that just replace TRUNCATE by DROP.
In case your partition is base on LIST, i.e. month number the solution would be this:
DECLARE
CURSOR PartTables IS
SELECT TABLE_NAME, PARTITION_NAME, HIGH_VALUE
FROM USER_TAB_PARTITIONS
WHERE TABLE_NAME = 'TABLENAME';
highValue INTEGER;
BEGIN
FOR aTab IN PartTables LOOP
EXECUTE IMMEDIATE 'BEGIN :ret := '||aTab.HIGH_VALUE||'; END;' USING OUT highValue;
IF highValue NOT IN (
EXTRACT(MONTH FROM SYSDATE),
EXTRACT(MONTH FROM ADD_MONTHS(SYSDATE, -1))
)
THEN
EXECUTE IMMEDIATE 'ALTER TABLE TABLENAME TRUNCATE PARTITION '||aTab.PARTITION_NAME||' UPDATE INDEXES';
END IF;
END LOOP;
END;
Based on your strange partition definition, the conditions would be
IF highValue NOT IN (
30*CEIL(TO_CHAR(SYSDATE, 'fmddd')/30),
30*CEIL(TO_CHAR(ADD_MONTHS(SYSDATE, -1), 'fmddd')/30)
)
THEN
but you may run into issues if you run the procedure between 26th - 31st of December.

Need assistance in creating a procedure to load the data into CSV file using plsql

I have a three tables as below.
Create table t1_Fact ( Cur_date Date, Name varchar2(10), Event varchar2(50), Price Number(10,0), TAX Number(10,0), Flag Number );
Create table App_Fact ( Application_ID Number, Application_Name varchar2(100), Application_Price Number, Appliation_Tax Number, Flag Number );
Create table t2 ( Table_Name Varchar2(100), Table_Columns Varchar(100), Table_Measure varchar2(100), t3_columns varchar2(100), t3_measures varchar2(100), t3_Where_Clause varchar2(100) );
Create table t3 ( Cur_date Date, Name varchar2(10), Event varchar2(50), Application_ID Number, Application_Name varchar2(100), Application_Price Number, Appliation_Tax Number, Price Number(10,0), TAX Number(10,0), Flag Number );
table t2 contains all the table names,column names of each source and destination tables and where clause conditions.
[t2 Details][1]
Here I need to insert the data from t3 to particular fact table by using group by the column names of fact table, measures and where clause by passing the fact table name as parameter.
Like if we pass t1_Fact table in procedure, we must get all the details from t2 and get the details from t3 and insert into t1_Fact and also save them into CSV file
I have tried the following procedure however I'm not able to insert the data into csv file
Create or Replace Procedure CommonProcedure(sourceTableName IN VARCHAR2) Is
tablename t2.Table_Name%TYPE;
destcolumns t2.Table_Columns%TYPE;
destMeasures t2.Table_Measure%TYPE;
whereClause t2.t3_Where_Clause%TYPE;
sourceColumns t2.t3_columns%TYPE;
sourceMeasures t2.t3_measures%TYPE;
q1 VARCHAR2(3000 BYTE);
pathInfo VARCHAR2(3000 BYTE);
v_file UTL_FILE.FILE_TYPE;
Cursor TableName Is SELECT Table_Name FROM t2;
Begin
--Path will be getting from another table using the function in the format of '/data/Oracle-files/Table_CSV'
pathInfo := getDBConfigParamValue('FILE_LOCATION');
Open c1;
Loop
Fetch TableName Into tablename;
Exit When TableName%notfound;
SELECT Table_Columns, Table_Measure, t3_columns, t3_measures INTO destcolumns,destMeasures,sourceColumns,sourceMeasures FROM t2 where Table_Name = tablename;
q1 := 'INSERT INTO '||tablename||'('||destColumns||','||destMeasures||')'||
' ( SELECT '||sourceColumns||','||sourceMeasures||','||sourceTableName
||' FROM '||sourceTableName||' GROUP BY '||sourceColumns||')';
Execute Immediate q1;
--Need to load the data into tablename.CSV
v_file := UTL_FILE.FOPEN('' || pathInfo ||',' ||destinationTableName ||'.csv' || '','W');
UTL_FILE.PUT_LINE(v_file,'' ||destColumns ||',' ||destMeasures ||'');
UTL_FILE.FCLOSE(v_file);
End Loop;
Close TableName;
End;
When I compile the above procedure getting following error
LINE/COL ERROR
-------- -----------------------------------------------------------------
47/13 PL/SQL: Statement ignored
47/23 PLS-00306: wrong number or types of arguments in call to 'FOPEN'
Please assist me further.
Thanks in advance.
PLS-00306: wrong number or types of arguments in call to 'FOPEN'
Your fopen call is only passing two arguments; you are concatenating a comma into the first value, rather than using it as an argument separator, so you are passing the constructed string '<pathInfo>,<destinationTableName>.csv' as the location, 'W' as the filename, and no third argument for the open mode.
You can see the problem if I highlight it:
v_file := UTL_FILE.FOPEN('' || pathInfo ||',' ||destinationTableName ||'.csv' || '','W');
^^^^^^^^
Continuing your pattern of concatenating empty strings (?) you have it the wrong side of a closing quote:
v_file := UTL_FILE.FOPEN('' || pathInfo ||'', destinationTableName ||'.csv' || '','W');
or maybe even:
v_file := UTL_FILE.FOPEN('' || pathInfo ||'', '' || destinationTableName ||'.csv' || '','W');
but you don't need to do all that confusing concatenation, you can just do:
v_file := UTL_FILE.FOPEN(pathInfo, destinationTableName ||'.csv', 'W');

IF-ELSE statement inside trigger in oracle

Here are the columns in my table, TB_KELUHAN
"IDKELUHAN" NUMBER(20,0) NOT NULL ENABLE,
"NAMA" VARCHAR2(10 BYTE),
"IDUNIT" NUMBER(10,0),
"TGL_KELUHAN" DATE DEFAULT sysdate,
"KELUHAN" VARCHAR2(200 BYTE),
"STATUS" VARCHAR2(10 BYTE),
"IDPEGAWAI" NUMBER(10,0),
"TGL_SELESAI" DATE DEFAULT sysdate,
"ID_JENISKELUHAN" NUMBER(5,0),
CONSTRAINT "TB_KELUHAN_PK" PRIMARY KEY ("IDKELUHAN")
I want a trigger that will update a row's TGL_SELESAI column to SYSDATE, when a row's STATUS becomes 'SELESAI'. Here is the text of the trigger I've tried:
TRIGGER SELESAI
AFTER UPDATE OF STATUS ON TB_KELUHAN
FOR EACH ROW
DECLARE
TGL_SELESAI DATE;
BEGIN
IF :new.STATUS = 'SELESAI'
THEN
TGL_SELESAI:=SYSDATE;
END IF;
END;
When I change the value of STATUS to "SELESAI", the corresponding TGL_SELESAI did not change. Why?
Your original code was setting a local PL/SQL variable, not the row's column and you were creating an AFTER UPDATE trigger, not a BEFORE UPDATE trigger. Try this:
CREATE OR REPLACE TRIGGER SELESAI
BEFORE UPDATE OF STATUS ON TB_KELUHAN
FOR EACH ROW
BEGIN
IF :new.STATUS = 'SELESAI'
THEN
:new.TGL_SELESAI := SYSDATE;
END IF;
END;

store multiple records into variable without using cursor

I have a table structure like as :
desc temp_table ;
Name Null? Type
student_name VARCHAR2(500)
Is_delete NUMBER(2)
using pl sql procedure I'm trying to store all values of above table into a variable.
If table has more then one row then I'm getting error like
ORA-01422: exact fetch returns more than requested number of rows
So without using cursor how can we store multiple row's in a variable??
Define two collection types:
CREATE OR REPLACE TYPE StringList IS TABLE OF VARCHAR2(4000);
/
CREATE OR REPLACE TYPE BooleanList IS TABLE OF NUMBER(1,0);
/
Use BULK COLLECT INTO:
CREATE OR REPLACE PROCEDURE UPDATE_TABLE
AS
Names StringList;
Del BooleanList;
BEGIN
DBMS_OUTPUT.ENABLE(1000000);
SELECT student_name,
Is_delete
BULK COLLECT INTO
Names,
Del
FROM temp_table
WHERE MODIFIED_DATE >= TRUNC( SYSDATE )
AND MODIFIED_DATE < TRUNC( SYSDATE ) + INTERVAL '1' DAY;
DBMS_OUTPUT.PUT_LINE ('Number Of Names: ' || Names.COUNT );
DBMS_OUTPUT.PUT_LINE ('Number Of Del: ' || Del.COUNT ); -- Will always be the same amount
FOR i IN 1 .. Names.COUNT LOOP
DBMS_OUTPUT.PUT_LINE ( Names(i) || ', ' || Del(i) );
END LOOP;
END;
/

Resources