Oracle can I use scalar functions in WHERE Clause? or a NULL issue - oracle

somehow I get never any results when I call:
select * from table_1 t1 where t1.c1 IS NOT NULL and trim(t1.c1) != '' ;
trim(t1.c1) != '' part causes problems actually i return nothing.

Oracle is peculiar in that the empty string ('') and NULL are the same thing. It is as if you are saying:
trim(t1.c1) != NULL
Such a statement will never be true. Try:
trim(t1.c1) IS NOT NULL

Related

why count(*) is slow even with index?

This is my query:
select count(*)
FROM TB_E2V_DOCUMENTOS_CICLO D
WHERE (D.TIPOCLIENTE = null or null is null)
AND (D.TIPODOCUMENTOCLIENTE = null or null is null)
AND (D.NUMDOCUMENTOCLIENTE = null or null is null)
AND (D.BA = null or null is null)
AND (D.FA = null or null is null)
AND (D.NOMBRECLIENTE = null or null is null)
AND (D.NUMTELEFONO = null or null is null)
AND (D.NUMSUSCRIPCION = null or null is null)
AND (D.TIPORECIBO in ('Recibo'))
AND (D.NUMRECIBO = null or null is null)
AND (TO_DATE(D.FECHAEMISION, 'yyyy/MM/dd') BETWEEN TO_DATE('2019-5-1', 'yyyy-MM-dd') AND TO_DATE('2020-2-18', 'yyyy-MM-dd'))
AND (D.MONTORECIBO = null or null is null)
AND (D.NUMPAGINAS = 0 or 0 = 0)
AND (D.NOMBREARCHIVO = null or null is null)
AND (D.NEGOCIO = null or null is null)
AND (D.NOMBREMETADATACARGA = null or null is null)
AND (D.FECHACARGA = TO_DATE(null) or TO_DATE(null) is null);
This query returns
And when I do a Xplain For:
The cost is very high, but this query uses the index. The query lasts 10 seconds approximately.
How can I improve the performance of the query?
I'm using Oracle 12c
Notes: All of the " and ( = null or null is null)" predicates will always evaluate to true; Oracle does not define null so null does not equal null, so instead if you want to check for null then use "is null"
select * from dual where null = null; -- returns no rows
select * from dual where not (null <> null); -- returns no rows
select * from dual where null is null; -- returns 1 row
select * from dual where not(null is not null); -- returns 1 row
As far as indexing goes, you need an index that is selective (i.e. return much fewer rows) and is present in the where clause predicate. In this case it looks like a function-based index on TO_DATE(D.FECHAEMISION, 'yyyy/MM/dd')
along with D.TIPORECIBO is in order. The INDEX SKIP SCAN is used in this case probably because D.TIPORECIBO is not the leading column; INDEX SKIP SCANs are slower then INDEX RANGE SCANs because it needs to read more index blocks.
There are a few factors involved here:
First, this query is using the second (or third) part of a composite index, resulting in the SKIP SCAN.
Take a look at all indexes on the table and see what kind of index is on TIPORECIBO.
It is likely that this isn't the leading column. You might improve the performance by creating an index with TIPORECIBO as leading column, but it is unlikely--this appears to be a "type" column that might have only a few values, and not a good candidate for an index.
The second issue is that Oracle uses the index to get a set of candidate rows, then goes to the data blocks themselves to get the rows for further filtering.
A select count(*) will perform much better if Oracle doesn't need to fetch the data blocks. This can be achieved by creating an index that contains all of the data needed for the filter.
In your case, an index on TIPORECIBO and FECHAEMISION would mean that Oracle could go to the index alone without needing to access the data blocks.
The third issue is that you are applying TO_DATE to the FECHAEMISION column. If this is a DATE datatype, then you don't need the conversion and it is causing you trouble. If you do need the conversion, an option would be a function-based index on TO_DATE(D.FECHAEMISION, 'yyyy/MM/dd').
To tune this particular query, you can try a function-based composite index:
CREATE INDEX TB_E2V_DOCUMENTOS_CICLO_FX1 ON TB_E2V_DOCUMENTOS_CICLO(FECHAEMISION, TO_DATE(D.FECHAEMISION, 'yyyy/MM/dd'))
Finally, this query is clearly being generated from code:
lines like AND (D.BA = null or null is null) seem to be a way of excluding portions of the WHERE clause when the front-end passes a NULL. This would possibly be AND (D.BA = 'X' or 'X' is null) if a value were provided for that parameter.
As such, be careful when tuning for the current set of parameters, as any change in what generated this query will impact the effectiveness of your tuning.
If you have a way to influence how this query is generated, it would be nice to simply exclude those non-event filters when the values are not provided, though Oracle ought to be able to handle them as-is.

What is the difference between "IS NOT NULL" and "NOT IN NULL"? Why these two Oracle queries return different results?

SELECT DUMMY FROM DUAL
WHERE DUMMY IS NOT NULL;
Result: Returns 'X';
SELECT DUMMY FROM DUAL
WHERE DUMMY NOT IN NULL;
Result: Returns nothing.
In Oracle binary expressions can evaluate to three states: TRUE, FALSE and NULL where NULL can be thought of as the same as a undefined or unknown value. Applying a binary operation to a NULL value will give a NULL output (and not, as you might expect, TRUE or FALSE):
Boolean Operation Result
----------------- ------
X = X TRUE
X = Y FALSE
X = NULL NULL
NULL = X NULL
NULL = NULL NULL
NULL IN ( NULL ) NULL
NOT TRUE FALSE
NOT FALSE TRUE
NOT NULL NULL
The query:
SELECT DUMMY FROM DUAL WHERE DUMMY NOT IN ( NULL )
is the equivalent of:
SELECT DUMMY FROM DUAL WHERE NOT( DUMMY = NULL )
And the WHERE clause evaluates NOT( DUMMY = NULL ) to NOT NULL which in turn evaluates to NULL. Since the WHERE filter evaluates to a non-TRUE value the row is excluded.
The IS NULL operation is specifically designed to test whether a value is NULL and will do what you intend where the equality = operator or IN operator will not.
So:
Boolean Operation Result
----------------- ------
NULL = NULL NULL
NULL IN ( NULL ) NULL
NULL IS NULL TRUE
DUMMY in DUAL is a varchar2, and you selected all DUMMY from DUAL that are not null (IS NOT NULL). DUAL has one row with DUMMY='X'.
Now you are saying that DUMMY is not IN a set of NULL, which makes no sense really and the select will return no result.
NULL is a special character, and is not zero. It represents the absence of real data (data which includes zeroes and empty spaces).

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.

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.

ORACLE SQL // IF ELSE?

I got a small problem in my SQL code :
LEFT JOIN
(SELECT *
FROM pilotage_usines_valeurs
WHERE c_indicateur IS NOT NULL) v
ON v.id_usine = d.id_usine
AND v.annee = 2015
AND V.MOIS = D.MOIS
AND V.C_INDICATEUR = pi1.c_indicateur
Sometime pi1.c_indicateur is null. How can i test it and write the line if pi1.c_indicateur is not null don't write it if pi1.c_indicateur is null ?
If I understand your intentions correctly I suggest you add the NOT NULL condition to the ON clause:
LEFT JOIN (SELECT *
FROM PILOTAGE_USINES_VALEURS
WHERE C_INDICATEUR IS NOT NULL) v
ON v.ID_USINE = d.ID_USINE
AND v.ANNEE = 2015
AND v.MOIS = D.MOIS
AND v.C_INDICATEUR = pi1.C_INDICATEUR
AND pi1.C_INDICATEUR IS NOT NULL
NVL is used to substitute null value by something else. Syntax is similar to
NVL (FIELD_TO_BE_TESTED_FOR_NULL, VALUE_IF_NULL);
Option 1:
Replace pi1.c_indicateur when null with some value so that V.C_INDICATEUR will never be equal to that value.
AND V.C_INDICATEUR = NVL(pi1.c_indicateur,'IMPOSSIBLE VALUE FOR V.C_INDICATEUR ');
Option 2:
Replace V.C_INDICATEUR with some value if null and replace pi1.c_indicateur with some other value, so that both will never match if NULL.
AND (V.C_INDICATEUR,'ABC') = NVL(pi1.c_indicateur,'DEF');

Resources