Oracle procedure 'with query' insert into table - oracle

I have created an Oracle SQL query in TOAD which works fine. I now need to put this in a procedure.
The query has to create two counts based on different criteria (I have used With Select) and insert these plus a date and location to a table.
The query that works is
with
Selected_animals as
( SELECT TO_CHAR(SYSDATE,'DD/MM/YYYY' ) as Report_Date,
loc.name location,
count(rran.id) as Count_exported
FROM rr_animals rran,
contact con,
locations loc,
names nam
WHERE con.connum = rran.connum
AND con.loc_id = loc.id
AND con.connum = nam.connum
AND nam.name_type = 'STAND'
AND nam.dob IS NOT NULL
AND rran.sex IS NOT NULL
AND rran.web_display = 'Y'
AND rran.web_description IS NOT NULL
AND rran.visit_end_date IS NULL
AND con.loc_id IS NOT NULL
AND con.datedl IS NULL
AND rran.hold_user IS NULL
AND rran.assess_status IS NULL
AND EXISTS (SELECT rrim.id
FROM rr_images rrim
WHERE rrim.image_type = 'KENNEL'
AND rrim.rran_id = rran.id
AND DBMS_LOB.GETLENGTH(rrim.image_object) >0
AND rrim.image_object IS NOT NULL)
group by loc.NAME ),
total_animals as
(select vbav.sitename as location,
count(vbav.rran_ID) as Count_available
from v_bx_all_animal_visits vbav
where visit_end_date is null
and concat != 'DELTD'
and concat != 'DSCD'
group by vbav.sitename)
select Total_animals.location,
Selected_animals.Report_date,
Selected_animals.count_exported,
Total_animals.count_available
from Selected_animals, total_animals
where total_animals.location = selected_animals.location(+)
I have looked at several ways that seem to write the procedure but nothing seems to work. Including which was added under the CREATE or REPLACE and before BEGIN:
( o_location out bx_webstats_export_available.LOCATION%TYPE,
o_date out bx_webstats_export_available.REPORT_DATE%TYPE,
o_exported out bx_webstats_export_available.COUNT_EXPORTED%TYPE,
o_available out bx_webstats_export_available.COUNT_AVAILABLE%TYPE )
Also added after the last where statement and before End:
INSERT INTO bx_webstats_export_available(location, report_date, count_export, count_available)
values (Total_animals.location,
Selected_animals.Report_date,
Selected_animals.count_exported,
Total_animals.count_available);
Can anyone help me get this query in a Procedure please?
This is the first time I have written a Procedure from scratch and I'm struggling with it.
Many thanks,

What is it you're trying to do? Insert the results of that select into a table? If so, the following ought to suffice:
create or replace procedure your_proc_name
as
begin
insert into bx_webstats_export_available(location, report_date, count_export, count_available)
with selected_animals as (select to_char(sysdate,'DD/MM/YYYY' ) as report_date,
loc.name location,
count(rran.id) as count_exported
from rr_animals rran,
contact con,
locations loc,
names nam
where con.connum = rran.connum
and con.loc_id = loc.id
and con.connum = nam.connum
and nam.name_type = 'STAND'
and nam.dob is not null
and rran.sex is not null
and rran.web_display = 'Y'
and rran.web_description is not null
and rran.visit_end_date is null
and con.loc_id is not null
and con.datedl is null
and rran.hold_user is null
and rran.assess_status is null
and exists (select rrim.id
from rr_images rrim
where rrim.image_type = 'KENNEL'
and rrim.rran_id = rran.id
and dbms_lob.getlength(rrim.image_object) >0
and rrim.image_object is not null)
group by loc.name),
total_animals as (select vbav.sitename as location,
count(vbav.rran_id) as count_available
from v_bx_all_animal_visits vbav
where visit_end_date is null
and concat != 'DELTD'
and concat != 'DSCD'
group by vbav.sitename)
select total_animals.location,
selected_animals.report_date,
selected_animals.count_exported,
total_animals.count_available
from selected_animals, total_animals
where total_animals.location = selected_animals.location(+);
end your_proc_name;
/
If not, then please explain a bit more about the requirements you're trying to satisfy.

Related

Optimize Insert statement

I have an insert block which inserts almost 5680969 rows and takes about 10 mins to execute. I tried to optimize using parallel hints and other things like summarizing queries. Can this block of query can be further optimized?? Any help will be much appreciated.
DECLARE
vblQueryName VARCHAR2(20);
BEGIN
vblQueryName:='060_745_085';
INSERT /*+ APPEND */ INTO TABLE_A
(
SOURCE,
SN,
CLMNUM,
CLAIMLINENUMBER,
CLMTYPE,
CLMTYPEDESC,
CLMCATEGORY,
MEMID,
ENRID,
RELFLAG,
MEMFIRSTNAME,
MEMLASTNAME,
GENDER,
DOB,
ADDR1,
ADDR2,
CITY,
STATE,
ZIP,
HOMEPHONE,
WORKPHONE,
LVLID1,
LVLDESC1,
LVLID2,
LVLDESC2,
LVLID3,
LVLDESC3,
LVLID4,
LVLDESC4,
LVLID5,
LVLDESC5,
LVLID6,
LVLDESC6,
LVLID7,
LVLDESC7,
LVLID8,
LVLDESC8,
LVLID9,
LVLDESC9,
LVLID10,
LVLDESC10,
FROMDATE,
TODATE,
SERVICEDATE,
RCVDATE,
PAIDDATE,
BILLTYPE,
POSCODE,
POSDESC,
SPECCODE,
SPECDESC,
DIAGCODE,
DIAGDESC,
FIRSTDIAGCODE,
FIRSTDIAGDESC,
SECONDDIAGCODE,
SECONDDIAGDESC,
THIRDDIAGCODE,
THIRDDIAGDESC,
FOURTHDIAGCODE,
FOURTHDIAGDESC,
FIFTHDIAGCODE,
FIFTHDIAGDESC,
SIXTHDIAGCODE,
SIXTHDIAGDESC,
SEVENTHDIAGCODE,
SEVENTHDIAGDESC,
EIGHTHDIAGCODE,
EIGHTHDIAGDESC,
NINTHDIAGCODE,
NINTHDIAGDESC,
TENTHDIAGCODE,
TENTHDIAGDESC,
PROCTYPE,
PROCCODE,
PROCDESC,
REVCODE,
DRGCODE,
MODIFIERCODE,
MODIFIERDESC,
CPT4_1,
CPT4_2,
CPT4_3,
HCPCS,
CPTII,
MODIFIERCODE2,
REVCODE1,
REVCODE2,
REVCODE4,
REVCODE3,
REVCODE5,
ICD9PROCCODE1,
ICD9PROCCODE2,
ICD9PROCCODE3,
ICD9PROCCODE4,
ICD9PROCCODE5,
ICD9PROCCODE6,
DRGTYPE,
DRGIDENTIFIER,
IPDAYS,
DISCHSTATUS,
TYPEOFBILL,
CLAIMSTATUS,
ADJCODE,
PROVID,
PROVNAME,
PROVIDERFIRSTNAME,
PROVIDERLASTNAME,
PROVNPI,
PROVZIPCODE,
SERVTYPECODE,
SERVTYPEDESC,
PROVTYPECODE,
PROVTYPEDESC,
SERVICECODE,
SPECROLLUPCODE,
SPECROLLUPDESC,
NWKID,
NWKNAME,
INNWK,
NETWORKTYPE,
SERVICEUNITS,
PAIDAMT,
BILLEDAMT,
ALLOWEDAMT,
PPOSAVINGAMT,
ENRPAIDAMT,
COINSAMT,
COPAYAMT,
DEDUCTAMT,
NOTALLOWEDAMT,
COBAMT,
PLANEXCLAMT,
LABTESTDATA,
SICCODE,
SICDESC,
SSN,
RCVMTH,
SRCFILENAME,
UDF1,
UDFC10,
UDFc19,
UDFc20,
ICDTYPE,
VHPAYORID
)
SELECT /*+PARALLEL(a,8) */
'SOURCE' AS SOURCE,
ROWNUM AS SN,
CASE UPPER(a.PROVIDER_NETWORK_PAR_INDICATOR) WHEN 'Y' THEN 'Y_' ELSE 'N_' END || a.CLAIM_NUMBER || a.CLAIM_LINE_NUMBER || ROWNUM AS CLMNUM,
a.CLAIM_LINE_NUMBER AS CLAIMLINENUMBER,
'MED' AS CLMTYPE,
'MEDICAL' AS CLMTYPEDESC ,
NULL AS CLMCATEGORY,
a.MEMID AS MEMID,
a.SUBSCRIBER_NUMBER AS ENRID,
NULL AS RELFLAG ,
UPPER(a.MEMBER_FIRST_NAME) AS MEMFIRSTNAME,
UPPER(a.MEMBER_LAST_NAME) AS MEMLASTNAME,
UPPER(a.MEMBER_GENDER) AS GENDER,
a.MEMBER_DATE_OF_BIRTH AS DOB,
a.MEMBER_ADDRESS_1 AS ADDR1,
a.MEMBER_ADDRESS_2 AS ADDR2,
a.MEMBER_CITY AS CITY,
a.MEMBER_STATE AS STATE,
a.MEMBER_ZIP AS ZIP,
a.MEMBER_PHONE AS HOMEPHONE,
NULL AS WORKPHONE,
'SOURCE' AS LVLID1,
'SOURCE' AS LVLDESC1,
NULL AS LVLID2,
NULL AS LVLDESC2,
NVL(lvl.VRSK_EMPLR_GRPID, REGEXP_REPLACE(a.subgroup_number,'[^a-zA-Z0-9]')) AS LVLID3,
NVL(lvl.EMPLOYER_GROUP_NM, REGEXP_REPLACE(a.subgroup_number,'[^a-zA-Z0-9]')) AS LVLDESC3,
NULL AS LVLID4,
NULL AS LVLDESC4,
NULL AS LVLID5,
NULL AS LVLDESC5,
NULL AS LVLID6,
NULL AS LVLDESC6,
NULL AS LVLID7,
NULL AS LVLDESC7,
NULL AS LVLID8,
NULL AS LVLDESC8,
NULL AS LVLID9,
NULL AS LVLDESC9,
NULL AS LVLID10,
NULL AS LVLDESC10,
a.SERVICE_START_DATE AS FROMDATE,
a.SERVICE_END_DATE AS TODATE,
a.SERVICE_START_DATE AS SERVICEDATE,
a.CLAIM_RECEIVED_DATE AS RCVDATE,
a.CLAIM_PROCESS_DATE AS PAIDDATE,
Decode(a.ENCOUNTER_TYPE_CODE, 'FCLTY', 'F', 'PROF', 'P', 'DENT', 'P') AS BILLTYPE,
a.PLACE_OF_SERVICE_CODE AS POSCODE,
NULL AS POSDESC,
e.ROLLUP_SPECCODE AS SPECCODE,
e.ROLLUP_SPECDESC AS SPECDESC,
COALESCE(a.PRIMARY_DIAGNOSIS_CODE,a.DIAGNOSIS_CODE_2,a.DIAGNOSIS_CODE_3,a.DIAGNOSIS_CODE_4,a.DIAGNOSIS_CODE_5) AS DIAGCODE,
NULL AS DIAGDESC,
a.PRIMARY_DIAGNOSIS_CODE AS FIRSTDIAGCODE,
NULL AS FIRSTDIAGDESC,
a.DIAGNOSIS_CODE_2 AS SECONDDIAGCODE,
NULL AS SECONDDIAGDESC,
a.DIAGNOSIS_CODE_3 AS THIRDDIAGCODE,
NULL AS THIRDDIAGDESC,
a.DIAGNOSIS_CODE_4 AS FOURTHDIAGCODE,
NULL AS FOURTHDIAGDESC,
a.DIAGNOSIS_CODE_5 AS FIFTHDIAGCODE,
NULL AS FIFTHDIAGDESC,
NULL AS SIXTHDIAGCODE,
NULL AS SIXTHDIAGDESC,
NULL AS SEVENTHDIAGCODE,
NULL AS SEVENTHDIAGDESC,
NULL AS EIGHTHDIAGCODE,
NULL AS EIGHTHDIAGDESC,
NULL AS NINTHDIAGCODE,
NULL AS NINTHDIAGDESC,
NULL AS TENTHDIAGCODE,
NULL AS TENTHDIAGDESC,
NULL AS PROCTYPE,
COALESCE(proc1.PROCCODE, proc2.PROCCODE, proc3.PROCCODE,a.PROCEDURE_CODE, NULLIF('I'||a.ICD_PROCEDURE_CODE_1,'I'), NULLIF('D'||a.AP_DRG,'D')) AS PROCCODE,
NULL AS PROCDESC,
CASE WHEN proc2.procTypeDesc='Rev Code' THEN proc2.PROCCODE END AS REVCODE,
proc3.PROCCODE AS DRGCODE,
NULL AS MODIFIERCODE,
NULL AS MODIFIERDESC,
CASE WHEN proc2.procTypeDesc='CPT4' THEN proc2.PROCCODE END AS CPT4_1,
NULL AS CPT4_2,
NULL AS CPT4_3,
CASE WHEN proc2.procTypeDesc='HCPCS' THEN proc2.PROCCODE END AS HCPCS,
NULL AS CPTII,
NULL AS MODIFIERCODE2,
CASE WHEN proc2.procTypeDesc='Rev Code' THEN proc2.PROCCODE END AS REVCODE1,
NULL AS REVCODE2,
NULL AS REVCODE4,
NULL AS REVCODE3,
NULL AS REVCODE5,
proc1.PROCCODE AS ICD9PROCCODE1,
REPLACE(a.ICD_PROCEDURE_CODE_2, '.') AS ICD9PROCCODE2,
REPLACE(a.ICD_PROCEDURE_CODE_3, '.') AS ICD9PROCCODE3,
NULL AS ICD9PROCCODE4,
NULL AS ICD9PROCCODE5,
NULL AS ICD9PROCCODE6,
NULL AS DRGTYPE,
NULL AS DRGIDENTIFIER,
NULL AS IPDAYS,
a.DISCHARGE_STATUS_CODE AS DISCHSTATUS,
NULL AS TYPEOFBILL,
NULL AS CLAIMSTATUS,
NULL AS ADJCODE,
coalesce(prov.rollupproviderid, a.provider_number) AS PROVID,
coalesce(prov.rollupprovidername,a.provider_name) AS PROVNAME,
NULL AS PROVIDERFIRSTNAME,
NULL AS PROVIDERLASTNAME,
NULL AS PROVNPI,
SubStr(a.PROVIDER_ZIP, 1, 5) AS PROVZIPCODE,
NULL AS SERVTYPECODE,
NULL AS SERVTYPEDESC,
NULL AS PROVTYPECODE,
NULL AS PROVTYPEDESC,
NULL AS SERVICECODE,
NULL AS SPECROLLUPCODE,
NULL AS SPECROLLUPDESC,
NVL(d.ROLLUPNWKID,a.PROVIDER_REGION_CODE) AS NWKID,
COALESCE(d.ROLLUPNWKNAME,a.PROVIDER_REGION_CODE) AS NWKNAME,
CASE UPPER(a.PROVIDER_NETWORK_PAR_INDICATOR) WHEN 'Y' THEN 'Y' ELSE 'N' END AS INNWK,
NULL AS NETWORKTYPE,
a.SERVICE_UNIT_COUNT AS SERVICEUNITS,
Nvl(a.PAID_AMOUNT,0) AS PAIDAMT,
Nvl(a.CHARGED_AMOUNT,0) AS BILLEDAMT,
Nvl(a.CHARGED_AMOUNT *0.54,0) AS ALLOWEDAMT,
NULL AS PPOSAVINGAMT,
NVL(a.COPAY_AMOUNT,0) + NVL(a.COINSURANCE_AMOUNT,0) + NVL(a.DEDUCTIBLE_AMOUNT,0) AS ENRPAIDAMT, -- corrected on /5/30/2013
Nvl(a.COINSURANCE_AMOUNT,0) AS COINSAMT,
Nvl(a.COPAY_AMOUNT,0) AS COPAYAMT,
Nvl(a.DEDUCTIBLE_AMOUNT,0) AS DEDUCTAMT,
Nvl(a.NOT_COVERED_AMOUNT,0) AS NOTALLOWEDAMT,
Nvl(a.COB_AMOUNT,0) AS COBAMT,
NULL AS PLANEXCLAMT,
NULL AS LABTESTDATA,
NULL AS SICCODE,
NULL AS SICDESC,
NULL AS SSN,
a.RECEIVEDMONTH AS RCVMTH,
a.SOURCEFILENAME AS SRCFILENAME,
'BCBSNC' AS UDF1 ,
a.SUBSCRIBER_NUMBER|| TO_CHAR(a.MEMBER_DATE_OF_BIRTH,'YYYYMMDD') AS UDFC10,--ICE176721
a.subgroup_number AS UDFc19,
a.benefit_package_id AS UDFc20,
CASE WHEN a.SERVICE_START_DATE>=to_date('20151001','YYYYMMDD') THEN 'ICD10' else 'ICD9' end as ICDTYPE,
payor.PAYORID AS VHPAYORID
FROM
HI0000001.HI_CLAIMS_SOURCE a
LEFT JOIN
HR_745_LOA_SOURCE lvl
ON
a.SUBGROUP_NUMBER = lvl.SUBGROUP_ID
LEFT JOIN
HR_745_NWK_CIGNA d
ON
a.PROVIDER_REGION_CODE = d.NWKID
AND
d.SOURCE = 'SOURCE'
LEFT JOIN
HR_745_SPEC_MERGED e
ON
a.PROVIDER_SPECIALTY_CODE = e.SRC_SPECCODE
AND
e.PAYER='BCBSNC'
LEFT JOIN
zzz_procs proc1
ON
'I'||REPLACE(a.ICD_PROCEDURE_CODE_1,'.') = proc1.proccode
LEFT JOIN
zzz_procs proc2
ON
CASE WHEN LENGTH(a.PROCEDURE_CODE)=4 AND SUBSTR(a.PROCEDURE_CODE,1,1)='0' THEN 'R'||SUBSTR(a.PROCEDURE_CODE,-3) ELSE a.PROCEDURE_CODE END = proc2.PROCCODE
LEFT JOIN
zzz_procs proc3
ON
'D'|| a.AP_DRG = proc3.proccode
LEFT JOIN
HR_GLOBAL_PAYORLIST payor
ON
payor.TABLENAME = 'HI_CLAIMS_BCBSNC'
LEFT JOIN
HR_745_PROVIDER prov
ON
'SOURCE' = prov.SOURCE
AND
UPPER(COALESCE(a.provider_number,'NULL')) = prov.provid
AND
UPPER(Nvl(a.provider_name, 'NULL')) = prov.provname
WHERE
a.ENCOUNTER_SERVICE_TYPE_CODE NOT IN ('06','02') AND a.ENCOUNTER_TYPE_CODE <>'CP'
AND
REGEXP_REPLACE(a.subgroup_number,'[^a-zA-Z0-9]') IS NOT NULL
AND
NVL(lvl.VRSK_EMPLR_GRPID, a.subgroup_number) NOT IN
(SELECT drp.lvl3id FROM hr_745_lvl3_drop drp WHERE source='BCBSNC')
AND
(NVL(lvl.VRSK_EMPLR_GRPID, a.subgroup_number)<>'539431' OR a.CLAIM_PROCESS_DATE<LAST_DAY(TO_DATE('2016-09','yyyy-mm')));
COMMIT;
DBMS_OUTPUT.PUT_LINE( 'Query Executed: ' || vblqueryName);
INSERT INTO VH_QUERYLOG(QueryName,CURTIME) VALUES(vblQueryName,SYSDATE);
EXCEPTION WHEN NO_DATA_FOUND THEN NULL;
END;
/
Add this statement before the INSERT:
execute immediate 'alter session enable parallel dml';
Remove all the hints and only use this one hint at the top:
/*+ APPEND PARALLEL */
This allows the entire statement to run in parallel, not just certain parts of the SELECT. Unless you're using an old, unsupported version of Oracle, you normally want to avoid listing the objects in the parallel hint. Using the parallel hint without a number will hopefully pick a better degree of parallelism, depending on the way the system is setup. If that doesn't work out, then I'd recommend trying different numbers. (In short, a higher DOP is always faster, but there are diminishing returns and it can steal resources from other statements.)
After you've done that, take a look at the explain plan for the INSERT. Ensure it's using LOAD AS SELECT and not CONVENTIONAL INSERT - that's how you tell the statement is using a direct-path write. The APPEND hint is tricky and there are many things that may prevent it from working correctly.
Then run the code and generate a SQL Monitor report like this: select dbms_sqltune.report_sql_monitor(sql_id => 'the insert SQL_ID') from dual;. That report will tell you which operation in the query is slow, if any. The explain plan will probably generate a few dozen lines, and without the SQL Monitor report you'll have to guess which part is slow. Some of the join conditions look complicated, I wouldn't be surprised if you see a few operations where the estimated rows are 1 but the actual are much higher, leading to NESTED LOOPs instead of HASH JOINs.
Those are high-level hints for getting started with a parallel INSERT. You can easily spend hours on a statement like this.

Insert Records in a Table without duplicating the records

I have this MySQL Statement. I want to execute this SQL repeatedly to insert the result into a Third table withoud duplicating the Records in Third Table.
SELECT `Client_ID`, `Client_RFID_Number`
FROM ciom_master AS a
WHERE (`Client_Active` ='Y' OR `Client_Active` ='y')
AND NOT EXISTS (
SELECT (`Client_Check_Out`)
FROM `cio_master` AS b
WHERE a.Client_ID = b.Client_ID
and Client_Check_Out = CURDATE() )
AND NOT EXISTS (
SELECT (`Client_Check_In`)
FROM `cio_master` AS c
WHERE a.Client_ID = c.Client_ID
and Client_Check_In = CURDATE())
I am attempting following Statement but it is throwing error
INSERT IGNORE INTO cio_alert (`Client_ID`, `Client_RFID_Number`, `Client_Check_Out`, `Client_Check_In`)
SELECT `ciom_master`.`Client_ID`, `ciom_master`.`Client_RFID_Number`,`cio_master`.`Client_Check_Out`, `cio_master`.`Client_Check_In` FROM ciom_master
INNER JOIN `cio_master` ON `ciom_master`.`Client_ID` = `ciom_master`.`Client_ID`
WHERE EXISTS
(SELECT `Client_ID`, `Client_RFID_Number`
FROM ciom_master AS a
WHERE (`Client_Active` ='Y' OR `Client_Active` ='y')
AND NOT EXISTS (
SELECT (`Client_Check_Out`)
FROM `cio_master` AS b
WHERE a.Client_ID = b.Client_ID
and Client_Check_Out = CURDATE() )
AND NOT EXISTS (
SELECT (`Client_Check_In`)
FROM `cio_master` AS c
WHERE a.Client_ID = c.Client_ID
and Client_Check_In = CURDATE())
AND (
SELECT `Client_Check_Out` FROM cio_master
WHERE ((`Client_Check_Out` IS NOT NULL AND `Client_Check_In` IS NULL)
OR (`Client_Check_Out` IS NULL AND `Client_Check_In` IS NULL)))
AND (
SELECT `Client_Check_In` FROM cio_master
WHERE ((`Client_Check_Out` IS NOT NULL AND `Client_Check_In` IS NULL)
OR (`Client_Check_Out` IS NULL AND `Client_Check_In` IS NULL)))
)
You didnt mention exist or not exist condition at the last select statement... u simply put the and condition without any exist or not exist or in or not in. Try to put any of the valid condition over there. And also in the first select statement y r u using same table twice and joining without any alias try to check that one also once.

Problems updating query with inner join

Can anyone please assist in getting this one query to work. I am trying to update status of a column in a table having joined to other tables
Here is the query
update
(select I.account_id, I.sts, I.name_id, CI.CRM_TYPE, I.comments
from PPInters I
inner join DW.CUST CT
on I.account_id = CT.account_id
where
I.sts is null
AND I.comments IS NOT NULL
AND CT.CUSTTYPe = 'INTNL') T
SET T.STS = 'D'
WHERE T.account_id IN (2000208927,380166014,190180447,166078041,105029075 )
I am getting "ORA-01779: cannot modify a column which maps to a non key-preserved table" error
What I am trying to do here is to set I.STS = 'D' for some 700 records pulled up using this query
select I.account_id, I.sts, I.name_id, CI.CRM_TYPE, I.comments
from PPInters I
inner join DW.CUST CT
on I.account_id = CT.account_id
where
I.sts is null
AND I.comments IS NOT NULL
AND CT.CUSTTYPe = 'INTNL'
I appreciate it
Assumming that account_id is a primary key kolumn in table PPInters,
that is it's value uniquely identifies records in this table:
UPDATE PPInters
SET STS = 'D'
WHERE account_id IN (
select I.account_id
/*, I.sts, I.name_id, CI.CRM_TYPE, I.comments */
from PPInters I
inner join DW.CUST CT
on I.account_id = CT.account_id
where
I.sts is null
AND I.comments IS NOT NULL
AND CT.CUSTTYPe = 'INTNL'
)
AND account_id IN (2000208927,380166014,190180447,166078041,105029075 )

How to compare multiple columns under same row in a table?

Following columns of a table should not be equal in my where clause.
cd_delivery_address
cd_mail_delivery_address
cd_st_code
cd_mail_st_code
cd_zip
cd_mail_zip
Please find my code snippet to achieve this:
select * from table cd
where
(
(cd_mail_delivery_address <> cd_delivery_address or
(cd_mail_delivery_address is null and cd_delivery_address is not null) or
(cd_mail_delivery_address is not null and cd_delivery_address is null)
)
and (
cd.cd_city <> cd.cd_mail_city or
(cd.cd_city is null and cd_mail_city is not null) or
(cd_city is not null and cd_mail_city is null))
and (
cd.st_code <> cd.cd_mail_st_code or
(cd.st_code is null and cd_mail_st_code is not null) or
(st_code is not null and cd_mail_st_code is null)
)
and (
cd.cd_zip <> cd.cd_mail_zip or
(cd.cd_zip is null and cd_mail_zip is not null) or
(cd_zip is not null and cd_mail_zip is null)
)
)
All columns are varchar2 and i get correct output for this code. But is it a better way to compare multiple columns in pl sql? can i improve this code? Any suggestion would be helpful.
You could replace your null checks with NVL function something like this:
...
NVL(cd_mail_delivery_address,'_') <> NVL(cd_delivery_address,'_')
...
it's definitively more readable but I'm not sure about query efficency
I have done it for two columns using a join:
select a.cd_delivery_address,b.cd_mail_delivery_address
from cd a inner join cd b
where a.cd_delivery_address <> b.cd_mail_delivery_address and
a.cd_delivery_address = b.cd_delivery_address
Here null checking condition will be omitted and will reduce the number of conditions, but there is a performance impact since join is involved.

Binding variables in dynamic PL/SQL

I have a dynamic PL/SQL that will construct the SELECT statement based on what the searching criteria input from the users,likes:
l_sql := 'SELECT * INTO FROM TABLEA WHERE 1=1 ';
IF in_param1 IS NOT NULL THEN
l_sql := l_sql || 'AND column1 = in_param1 ';
END IF;
IF in_param2 IS NOT NULL THEN
l_sql := l_sql || 'AND column2 = in_param2 ';
END IF;
...................................
IF in_paramXX IS NOT NULL THEN
l_sql := l_sql || 'AND columnXX = in_paramXX ';
END IF;
To reduce the hard parse overhead , I consider to use the binding variables. However , it is difficult to manage when supplying the actual values to the binding variables as there are so many binding variables and combination of the generated SELECT statement . I cannot use the method of DBMS_SESSION.set_context() introduced at http://www.dba-oracle.com/plsql/t_plsql_dynamic_binds.htm because my account has no right to use this package. Besides , I want the generated SQL only contains the conditions on the fields that the user did not leave empty. So I cannot change the dynamic SQL to something likes
SELECT * INTO FROM TABLEA WHERE 1=1
and ( in_param1 is NULL or column1 = in_param1)
and ( in_param2 is NULL or column2 = in_param2)
...............................................
and ( in_paramXX is NULL or columnXX = in_paramXX)
So , I want to try to use the DBMS_SQL method .Can anyone give an example about how to use DBMS_SQL to call dynamic SQL with binding variables? Especially , how can I get the result executed from DBMS_SQL.execute() to the SYS_REFCURSOR , something like :
open refcursor for select .... from
The oracle version that I use is 10g and it seems that the oracle 10g does not have DBMS_Sql.To_Refcursor()
In your Oracle version you can apply some tricks to your query in order to do this. The idea is to use a query in the following form:
select *
from
(select
:possibleParam1 as param1
-- do the same for every possible param in your query
:possibleParamN as paramN
from dual
where rownum > 0) params
inner join
-- join your tables here
on
-- concatenate your filters here
where
-- fixed conditions
then execute it with:
open c for query using param1, ..., paramN;
It works by using DUAL to generate a fake row with every single param, then inner joining this fake row to your real query (without any filters) using only the filters you want to apply. This way, you have a fixed list of bind variables in the SELECT list of the params subquery, but can control which filters are applied by modifying the join condition between params and your real query.
So, if you have something like, say:
create table people (
first_name varchar2(20)
last_name varchar2(20)
);
you can construct the following query if you just want to filter on first name
select *
from
(select
:first_name as first_name,
:last_name as last_name
from dual
where rownum > 0) params
inner join
people
on
people.first_name = params.first_name;
and this if you want to filter on both first_name and last_name
select *
from
(select
:first_name as first_name,
:last_name as last_name
from dual
where rownum > 0) params
inner join
people
on
people.first_name = params.first_name and
people.last_name = params.last_name;
and in every case you would execute with
open c for query using filterFirstName, filterLastName;
It is important for performance to use the where rownum > 0 with DUAL as it forces Oracle to "materialize" the subquery. This usually makes DUAL stop interfering with the rest of the query. Anyway, you should check the execution plans to be sure Oracle is not doing anything wrong.
In 10g a DBMS_SQL cursor can't be changed into a Ref Cursor. Going through a result set through DBMS_SQL is tortuous since, as well as looping through the rows, you also have to loop through the columns in a row.
I want the generated SQL only contains
the conditions on the fields that the
user did not leave empty
Is that purely for performance reasons ? If so, I suggest you work out what the practical execution plans are and use separate queries for them.
For example, say I'm searching on people and the parameters are first_name, last_name. gender, date_of_birth. The table has indexes on (last_name,first_name) and (date_of_birth), so I only want to allow a query if it specifies either last_name or date_of_birth.
IF :p_firstname IS NOT NULL and :p_lastname IS NOT NULL THEN
OPEN cur FOR
'SELECT * FROM PEOPLE WHERE last_name=:a AND first_name=:b AND
(date_of_birth = :c or :c is NULL) AND (gender = :d or :d IS NULL)' USING ....
ELSIF :p_lastname IS NOT NULL THEN
OPEN cur FOR
'SELECT * FROM PEOPLE WHERE last_name=:a AND
(date_of_birth = :c or :c is NULL) AND (gender = :d or :d IS NULL)' USING ....
ELSIF :p_dateofbirth IS NOT NULL THEN
OPEN cur FOR
'SELECT * FROM PEOPLE WHERE date_of_birth=:a AND
(first_name=:b OR :b IS NULL) AND (gender = :d or :d IS NULL)' USING ....
ELSE
RAISE_APPLICATION_ERROR(-20001,'Last Name or Date of Birth MUST be supplied);
END IF;

Resources