SQL optimization with indexes - sql

I have been trying hard to optimize below query using indexes in place of where clause. can any one help on the same. Data volume is very high so I want to optimize it using indexing or anyother way?
Query goes like this:
SELECT *
FROM
(SELECT
a.*,
rownum as row_num
FROM
(SELECT DISTINCT
lot.lot_no AS lotNo, lot.sel as sel,
lot.C_ARRIVAL_NOTICE_NO AS arrNoticeNo,
lot.C_SHIPMENT_DIRECTION AS shipmentDirection,
lot.C_SENDERS_REFERENCE_NUM AS externalReference,
lot.booking_seq AS bookingNo,lot.shipper AS shipperCode,
nvl(lot.shipper_name ,lot.shipper_addr1) AS shipperName,
NVL2 (lot.commdesc, lot.commdesc || ' ', '') || NVL2 (lot.comdesc1,lot. comdesc1 || ' ', '') || NVL2 (lot.comdesc2, lot.comdesc2 || ' ', '') || NVL2 (lot.comdesc3, lot.comdesc3 || ' ', '') || NVL2 (lot.comdesc4, lot.comdesc4 || ' ', '') || NVL2 (lot.comdesc5, lot.comdesc5 || ' ', '') || NVL2 (lot.comdesc6,lot. comdesc6 || ' ', '') || NVL2 (lot.comdesc7,lot. comdesc7 || ' ', '') || NVL2 (lot.comdesc8, lot.comdesc8 || ' ', '') || NVL2 (lot.comdesc9, lot.comdesc9, '') AS description,
lot.lot_qty AS pieces, lot.lot_wght AS weight,
lot.lot_cube AS cube,
to_char(lot.input_date, 'dd-Mon-YYYY') AS lotDate,
lot.e_m AS e_m, lot.warehouse AS warehouse,
to_char(lot.in_date , 'dd-Mon-YYYY') AS inDate,
lot.in_time AS inTime, lot.hold AS hold,
to_char(lot.sail_date, 'dd-Mon-YYYY') AS sailDate,
to_char(lot.sail_date, 'dd-Mon-YYYY') AS etdDate,
lot.container AS container,
lot.oml_bl_no AS billOfLadingNumber,
lot.reference AS fileNumber,
lot.inland_carrier AS trucker,
lot.pro_number AS proNumber,
lot.comments AS exceptions, lot.vessel AS vessel,
lot.cstatus AS status, lot.voyage AS voyage,
(SELECT count(*) FROM tra_shipment_status
WHERE c_reference = lot.lot_no AND i_status_code = '857940') as transmitcount,
(SELECT c_finalcfs_code FROM imp_bl_top
WHERE inv_no = lot.C_Arrival_Notice_No) as cfsCode,
'STI_COUNTRY_US' AS schemaName
FROM
itemdata lot
WHERE
lot.in_date BETWEEN TO_DATE('27-FEB-2017 00:00', 'DD-MON-YYYY HH24:MI')
AND TO_DATE('29-MAR-2017 23:59', 'DD-MON-YYYY HH24:MI')
AND lot.sel IS NOT NULL
AND (lot.C_ARRIVAL_NOTICE_NO IS NOT NULL OR
lot.C_SHIPMENT_DIRECTION ='IO')
AND lot.I_STATUS > 0 AND Lot.Cstatus = 'D'
ORDER BY
lot.lot_no desc, lot.in_date desc) a
WHERE
rownum <= 60)
WHERE
row_num >= 1

Related

How to remove/avoid a particular string in SQL output

Below is the SQL Query:
select '"'|| trim(COLUMN1) ||'"|"'|| trim(COLUMN2) ||'"|"'|| trim(COLUMN3) ||'"'
from TABLE1 where ....
The output I get is:
"DATA1"|""|"DATA3"
"DATA4"|""|"DATA6"
But, I want it to display the output like below:
"DATA1"||"DATA3"
"DATA4"||"DATA6"
That means, if there is some null value of a particular column, it must not display "". I hope you all got it.
Please help me achieving this, as I am automating this process where in the output file goes directly to the destination application (i.e. I won't be able to modify it manually).
Thanks!
You can use case to avoid printing anything if the column is null
select '"'|| trim(COLUMN1) || '"|' ||
case when COLUMN2 is null then '' else '"' || trim(COLUMN2) || '"' end
|| '|"' || trim(COLUMN3) ||'"'
from TABLE1 where ....
You can use NVL2( value, value_if_not_null, value_if_null ):
SELECT NVL2( COLUMN1, '"' || TRIM( COLUMN1 ) || '"', NULL )
|| '|' || NVL2( COLUMN2, '"' || TRIM( COLUMN2 ) || '"', NULL )
|| '|' || NVL2( COLUMN3, '"' || TRIM( COLUMN3 ) || '"', NULL )
FROM table1
WHERE -- ...
Or CASE:
SELECT CASE WHEN COLUMN1 IS NOT NULL THEN '"' || TRIM( COLUMN1 ) || '"' END
|| '|' || CASE WHEN COLUMN2 IS NOT NULL THEN '"' || TRIM( COLUMN2 ) || '"' END
|| '|' || CASE WHEN COLUMN3 IS NOT NULL THEN '"' || TRIM( COLUMN3 ) || '"' END
FROM table1
WHERE -- ...
replace Function
select replace('"'|| trim(COLUMN1) ||'"|"'|| trim(COLUMN2) ||'"|"'|| trim(COLUMN3) ||'"', '""','')
from TABLE1 where ....
Use
REPLACE(String, '""', '')
select REPLACE('"'|| trim(COLUMN1) ||'"|"'|| trim(COLUMN2) ||'"|"'|| trim(COLUMN3) ||'"', '""', '') from TABLE1 where ....

How to make single SQL query without using UNION for more than 2 SQL statements?

SELECT 'INITIALIZE' AS PROCESS_DESC,
floor((MAX(EXEC_DATE)-MIN(EXEC_DATE))*24)
|| ' HOURS '
|| mod(floor((MAX(EXEC_DATE)-MIN(EXEC_DATE))*24*60),60)
|| ' MINUTES '
|| mod(floor((MAX(EXEC_DATE)-MIN(EXEC_DATE))*24*60*60),60)
|| ' SECS ' time_difference
FROM spool_table
WHERE process_desc ='INITIALIZE'
AND to_date(EXEC_DATE, 'DD-MON-YYYY') =
(SELECT to_date(EXEC_DATE, 'DD-MON-YYYY')=
FROM spool_table
WHERE process_desc='INITIALIZE'
)
UNION ALL
SELECT 'PRELIM' AS PROCESS_DESC,
floor((MAX(EXEC_DATE)-MIN(EXEC_DATE))*24)
|| ' HOURS '
|| mod(floor((MAX(EXEC_DATE)-MIN(EXEC_DATE))*24*60),60)
|| ' MINUTES '
|| mod(floor((MAX(EXEC_DATE)-MIN(EXEC_DATE))*24*60*60),60)
|| ' SECS ' time_difference
FROM spool_table
WHERE process_desc ='PRELIM'
AND to_date(EXEC_DATE, 'DD-MON-YYYY')=
(SELECT to_date(MAX(EXEC_DATE), 'DD-MON-YYYY')
FROM spool_table
WHERE process_desc='PRELIM'
)
You can use FIRST (or LAST) in this case to find the min datetime on the latest date:
with cte (process_desc, max_exec_date, min_exec_date) as (
select
process_desc,
max(exec_date) max_exec_date,
min(exec_date) keep (dense_rank last order by trunc(exec_date) nulls first) min_exec_date
from spool_table s
where process_desc in ('PRELIM', 'INITIALIZE') -- include or exclude what process you want here
group by process_desc
)
select
process_desc,
floor((max_exec_date-min_exec_date)*24) || ' HOURS ' ||
mod(floor((max_exec_date-min_exec_date)*24*60),60) || ' MINUTES ' ||
mod(floor((max_exec_date-min_exec_date)*24*60*60),60)
|| ' SECS ' time_difference
from cte;
the CTE is there to clarify the query. You can put it as a subquery if you want or even without a subquery like this:
select
process_desc,
floor((max(exec_date)-min(exec_date) keep (dense_rank last order by trunc(exec_date) nulls first))*24) || ' HOURS ' ||
mod(floor((max(exec_date)-min(exec_date) keep (dense_rank last order by trunc(exec_date) nulls first))*24*60),60) || ' MINUTES ' ||
mod(floor((max(exec_date)-min(exec_date) keep (dense_rank last order by trunc(exec_date) nulls first))*24*60*60),60)
|| ' SECS ' time_difference
from spool_table s
where process_desc in ('PRELIM', 'INITIALIZE')
group by process_desc;
A bit Naive way is using correlated subquery:
select process_desc,
floor((max(exec_date)-min(exec_date))*24)
|| ' HOURS '
|| mod(floor((max(exec_date)-min(exec_date))*24*60),60)
|| ' MINUTES '
|| mod(floor((max(exec_date)-min(exec_date))*24*60*60),60)
|| ' SECS ' time_difference
from spool_table s
where process_desc in ('PRELIM', 'INITIALIZE')
and trunc(exec_date) = (
select trunc(max(exec_date))
from spool_table t
where t.process_desc = s.process_desc
)
group by process_desc;

Refactor sql query that uses PostGIS functions

I have a query that looks like this:
SELECT *,
ST_Distance(
ST_GeographyFromText('SRID=4326;POINT(' || users.longitude || ' ' || users.latitude || ')'),
ST_GeographyFromText('SRID=4326;POINT(-84.334078 45.273343)')) as distance
FROM users
WHERE ST_DWithin(
ST_GeographyFromText('SRID=4326;POINT(' || users.longitude || ' ' || users.latitude || ')'),
ST_GeographyFromText('SRID=4326;POINT(-84.334078 45.273343)'),
2000
)
ORDER BY distance ASC;"
I've see some repetitions here. I'm wondering is there any way to make this query more readable?
Lateral join:
select *, ST_Distance(a, b) distance
from
users,
ST_GeographyFromText('SRID=4326;POINT(' || users.longitude || ' ' || users.latitude || ')') a,
ST_GeographyFromText('SRID=4326;POINT(-84.334078 45.273343)') b
where ST_DWithin(a, b, 2000)
order by distance asc;

How to sort data in Oracle SQL with sub query and wm_concat

Below is a sub-query of a bigger query, what I am trying to do is to get last 5 documents sorted by SL_DT in descending.
I always get an error that the right parenthesis is missing, I have also considered using row_number() over (order by pa.last_modified_date desc) but it doesn't work.
SELECT REPLACE (
wm_concat( SL_TXN_CODE
|| ' - '
|| SL_NO
|| '('
|| SL_DT
|| ') - '
|| SUM (SL_QTY)),
',',
' ,'
)
FROM STK_LEDGER
WHERE ROWNUM <= 5
AND SL_ITEM_CODE =
(SELECT IDH_ITEM_CODE
FROM AA_ITEM_DEFINATION_HEAD
WHERE IDH_SUPP_BC_1 = '111' OR IDH_ITEM_CODE = '111')
AND SL_TXN_TYPE IN ('SARTN', 'GRN', 'LTRFI')
AND SL_LOCN_CODE NOT IN ('D2', 'D4', 'D5')
GROUP BY SL_TXN_CODE, SL_NO, SL_DT
ORDER BY SL_DT DESC
Please suggest the best way to sort SL_DT in descending and getting the 5 records only. As you can see that I need all data in one single field.
The database is Oracle 10g.
Thanks in advance.
SELECT VALUE
FROM (SELECT VALUE, ROWNUM AS ROW_NUM
FROM (SELECT REPLACE(WM_CONCAT(SL_TXN_CODE || ' - ' || SL_NO || '(' ||
SL_DT || ') - ' || SUM(SL_QTY)),
',',
' ,') AS VALUE
FROM STK_LEDGER
WHERE SL_ITEM_CODE =
(SELECT IDH_ITEM_CODE
FROM AA_ITEM_DEFINATION_HEAD
WHERE IDH_SUPP_BC_1 = '111'
OR IDH_ITEM_CODE = '111')
AND SL_TXN_TYPE IN ('SARTN', 'GRN', 'LTRFI')
AND SL_LOCN_CODE NOT IN ('D2', 'D4', 'D5')
GROUP BY SL_TXN_CODE, SL_NO, SL_DT
ORDER BY SL_DT DESC))
WHERE ROW_NUM <= 5

How to use Search multiple LIKE for IN condition in DB2

SELECT *
FROM XYZ
WHERE column1 IN (X1,Y1,Z1);
I want to use LIKE with this select query; how can I write LIKE statement with IN, similar to the query as below:
SELECT *
FROM XYZ
WHERE column1 LIKE IN ($P{COLUMN});
ANOTHER EXAMPLE:-
select * from ( select REPLACE(REFEV_VEH_TYPE, ' ', '') ||
REPLACE(REFEV_CATEGORY, ' ', '') || REPLACE(REFEV_USAGE, ' ', '') ||
REPLACE(REFEV_BODY_CODE, ' ', '') as UC from TREF_ENF_VEHICLE_TYPE )
aa where aa.UC LIKE ('%06TBISUM%')
UC
------
06TBISUM
select * from ( select REPLACE(REFEV_VEH_TYPE, ' ', '') ||
REPLACE(REFEV_CATEGORY, ' ', '') || REPLACE(REFEV_USAGE, ' ', '') ||
REPLACE(REFEV_BODY_CODE, ' ', '') as UC from TREF_ENF_VEHICLE_TYPE )
aa where aa.UC LIKE ('%B')
UC
----------
06TGISJB
06TGITJB
select * from ( select REPLACE(REFEV_VEH_TYPE, ' ', '') ||
REPLACE(REFEV_CATEGORY, ' ', '') || REPLACE(REFEV_USAGE, ' ', '') ||
REPLACE(REFEV_BODY_CODE, ' ', '') as UC from TREF_ENF_VEHICLE_TYPE )
aa where aa.UC LIKE ('%BAS')
UC
----------
06BCIBAS
05BCABAS
05BCBBAS
The result that i want to know is :
select * from (
select REPLACE(REFEV_VEH_TYPE, ' ', '') || REPLACE(REFEV_CATEGORY, ' ', '') || REPLACE(REFEV_USAGE, ' ', '') || REPLACE(REFEV_BODY_CODE, ' ', '') as UC
from TREF_ENF_VEHICLE_TYPE ) aa
where aa.UC IN LIKE ('%06TBISUM%', '%B','%BAS').
UC
------
06TBISUM
06TGISJB
06TGITJB
06BCIBAS
05BCABAS
05BCBBAS
The parameter that i use is $P{COLUMN}.
i want to search multiple by $P{COLUMN} parameter using IN LIKE($P{COLUMN}).Anyone know about this?
A LIKE operation is functionally equivalent to multiple OR operations.
So..
SELECT *
FROM XYZ
WHERE ( column1 like 'X1' OR column1 like 'X2' OR column1 like 'X3' )
Try
where REGEXP_LIKE(aa.UC,'.+[06TBISUM.*|B|BAS].+')
Replace + with * (if I put * in it translates to italics)
You can't use a single variable as an array in DB2, but you can split it with a recursive CTE.
Here's a version without needing to define a function:
WITH Split AS (SELECT '' AS value, txt, LOCATE(',', txt) AS nxt
FROM (VALUES($P{COLUMN})) t(txt)
UNION ALL
SELECT DECODE(nxt, 0, txt, SUBSTR(txt, 1, nxt - 1)),
DECODE(nxt, 0, '', SUBSTR(txt, nxt + 1)),
DECODE(txt, '', 0, LOCATE(',', txt, nxt + 1))
FROM Split
WHERE LENGTH(txt) > 0),
SearchData AS (SELECT value
FROM Split
WHERE value <> '')
SELECT uc
FROM (SELECT REPLACE(refev_veh_type, ' ', '')
|| REPLACE(refev_category, ' ', '')
|| REPLACE(refev_usage, ' ', '')
|| REPLACE(refev_body_code, ' ', '') AS uc
FROM TRef_ENF_Vehicle_Type ) T
JOIN SearchData
ON T.uc LIKE SearchData.value
(not tested, as I don't have a DB2 instance handy)
$P{COLUMN} is assumed to contain the following string: '%06TBISUM%,%B,%BAS'.