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;