Insert from remote table using unpivot - oracle11g
So, there's a table for scheduling in our organization and reporting data from it. A schedule line has a column for each day of the week with values of 'Y' or 'N' depending on whether or not there is a meeting on that day. I have managed to use UNPIVOT to do this in a simple select, but, unfortunately, our needs are more complex than that.
I need to insert into a local table with a query from the schedule table on a remote table over a DB_Link, which is unpivoted, something like:
SELECT *
FROM (SELECT class_nbr,
TERM,
MON,
TUES,
WED,
THURS,
FRI,
SAT,
SUN
FROM schedule_tbl) sched
UNPIVOT (wkDay FOR DayWeek IN (MON, TUES, WED, THURS, FRI, SAT, SUN)) piv
WHERE piv.WkDay = 'Y'
Again, this works fine when I run it in Sql Developer against the server where the schedule_tbl lives. I get results like
Class_nbr TERM DayWeek
1234 Fall MON
1234 Fall Wed
....
However, amazingly, when I try to insert the result of this from a different server like
INSERT INTO other_table (class_nbr, TERM, DayWeek)
SELECT *
FROM (SELECT class_nbr,
TERM,
MON,
TUES,
WED,
THURS,
FRI,
SAT,
SUN
FROM schedule_tbl#db_link) sched
UNPIVOT (wkDay FOR DayWeek IN (MON, TUES, WED, THURS, FRI, SAT, SUN)) piv
WHERE piv.WkDay = 'Y'
what happens is that only rows with DayWeek = 'MON' are inserted. The actual number of Monday rows which should be inserted are. I'm not sure where this is breaking down. If I change the order of the UNPIVOT columns, making TUES the first one, then only the Tuesday rows are inserted (again, the correct number).
Edit: I think I can share my actual code here. Keep in mind that if I take this exact query to the remote database and remove the dblinks, I am getting more than just Monday rows:
SELECT '%processinstance',
0 ,
crse_id ,
crse_offer_nbr ,
strm ,
session_code ,
class_section ,
subject ,
institution ,
facility_id ,
' ' ,
' ' ,
'0001484' ,
'4' ,
PDB_DE0120_TRM_ID ,
subject || catalog_nbr ,
strm || class_nbr ,
to_char ( start_dt , 'YYYYMMDD' ) ,
to_char ( end_dt , 'YYYYMMDD' ) ,
DECODE(DAYWEEK,'MON', 'M', 'TUES','T', 'WED','W', 'THURS','R', 'FRI','F', 'SAT','S', 'SUN','X'),
nvl ( to_char ( meeting_time_start ,'HH24MI' ) ,'9999' ) ,
nvl ( to_char ( meeting_time_end ,'HH24MI' ) ,'9999' ) ,
' ' ,
' ' ,
' ' ,
0 ,
'S' ,
'C' ,
decode ( instruction_mode ,'HB' ,'X' ,'DL' ,'X' ,'N' ) ,
' ' ,
' ' ,
' ' ,
' ' ,
' ' ,
'E' ,
SYSDATE ,
' ' ,
SYSDATE,
' ' ,
' '
FROM (SELECT A.crse_id ,
A.crse_offer_nbr ,
A.strm ,
A.session_code ,
A.class_section ,
B.institution ,
A.facility_id ,
B.instruction_mode,
B.SUBJECT,
B.CATALOG_NBR,
A.meeting_time_start,
A.meeting_time_end,
B.START_DT,
B.END_DT,
B.CLASS_NBR,
C.PDB_DE0120_TRM_ID,
MON,
TUES,
WED,
THURS,
FRI,
SAT,
SUN
FROM PS_CLASS_MTG_PAT#CSDV1 A
INNER JOIN PS_CLASS_TBL#CSDV1 B
ON A.STRM = B.STRM AND
A.CRSE_ID = B.CRSE_ID AND
A.CLASS_SECTION = B.CLASS_SECTION
INNER JOIN PS_FSC_SRPT_TRM_VW#CSDV1 C
ON C.STRM = B.STRM AND
C.ACAD_CAREER = 'CRED'
WHERE A.STRM = '2182' AND
(B.CLASS_STAT <> 'X' OR
(B.ENRL_TOT > 0 AND
B.ENRL_STAT <> 'C')) AND
B.acad_group NOT IN ( '11','12','13','23','80','99' )) B
UNPIVOT EXCLUDE NULLS (wkDay FOR DayWeek IN ( MON AS 'MON', TUES AS 'TUES', WED AS 'WED', THURS AS 'THURS', FRI AS 'FRI', SAT AS 'SAT', SUN AS 'SUN')) piv
WHERE piv.wkDay = 'Y';
Second update: As requested, I am pasting the corrected query:
SELECT '%processinstance',
0 ,
crse_id ,
crse_offer_nbr ,
strm ,
session_code ,
class_section ,
subject ,
institution ,
facility_id ,
' ' ,
' ' ,
'0001484' ,
'4' ,
PDB_DE0120_TRM_ID ,
subject || catalog_nbr ,
strm || class_nbr ,
to_char ( start_dt , 'YYYYMMDD' ) ,
to_char ( end_dt , 'YYYYMMDD' ) ,
DECODE(DAYWEEK,'MON', 'M', 'TUES','T', 'WED','W', 'THURS','R', 'FRI','F', 'SAT','S', 'SUN','X'),
nvl ( to_char ( meeting_time_start ,'HH24MI' ) ,'9999' ) ,
nvl ( to_char ( meeting_time_end ,'HH24MI' ) ,'9999' ) ,
' ' ,
' ' ,
' ' ,
0 ,
'S' ,
'C' ,
decode ( instruction_mode ,'HB' ,'X' ,'DL' ,'X' ,'N' ) ,
' ' ,
' ' ,
' ' ,
' ' ,
' ' ,
'E' ,
' ' ,
' ' ,
' '
FROM (SELECT A.crse_id ,
A.crse_offer_nbr ,
A.strm ,
A.session_code ,
A.class_section ,
B.institution ,
A.facility_id ,
B.instruction_mode,
B.SUBJECT,
B.CATALOG_NBR,
A.meeting_time_start,
A.meeting_time_end,
B.START_DT,
B.END_DT,
B.CLASS_NBR,
C.PDB_DE0120_TRM_ID,
MON,
TUES,
WED,
THURS,
FRI,
SAT,
SUN
FROM PS_CLASS_MTG_PAT#CSDV1 A
INNER JOIN PS_CLASS_TBL#CSDV1 B
ON A.STRM = B.STRM AND
A.CRSE_ID = B.CRSE_ID AND
A.CLASS_SECTION = B.CLASS_SECTION
INNER JOIN PS_FSC_SRPT_TRM_VW#CSDV1 C
ON C.STRM = B.STRM AND
C.ACAD_CAREER = 'CRED'
WHERE A.STRM = '2182' AND
(B.CLASS_STAT <> 'X' OR
(B.ENRL_TOT > 0 AND
B.ENRL_STAT <> 'C')) AND
B.acad_group NOT IN ( '11','12','13','23','80','99' )) B
UNPIVOT EXCLUDE NULLS (wkDay FOR DayWeek IN ( MON AS 'MON', TUES AS 'TUES', WED AS 'WED', THURS AS 'THURS', FRI AS 'FRI', SAT AS 'SAT', SUN AS 'SUN')) piv
WHERE piv.wkDay = 'Y';
This isn't a completely satisfactory solution, but it is working for me. If I remove two expressions from my select clause (any two columns), this issue disappears. This is obviously a previously unknown Oracle issue involving DB Links, as if I take the same query and run it on the remote server where the tables live it is not present, and there is nothing in the Oracle documentation regarding DB Links about this. I will at some point attempt to raise it with them.
Related
Sqlite sum time
I have a table with a column that contained time duration of events. It it formatted as 'h:mm:ss' I found the function strftime - but according to the manual, it requires the format 'hh:mm:ss' can someone tell me how i can sum up the duration without recreating the sql table?
Is this what you want ? with t as ( select '4:02:01' as v union all select '9:30:12' union all select '2:14:00' ), diff as ( select sum(strftime('%s', '0'||v) - strftime('%s', '00:00:00')) as v from t ) select (v/3600) || ' hours, ' || (v%3600/60) ||' minutes, ' || (v%60) || ' seconds.' from diff https://www.db-fiddle.com/f/2SNbFYQv2zYiCE4gw5bhzi/0
You can use time() and strftime(): select time(sum( strftime('%s', case length(timecolumn) when 7 then '0' else '' end || timecolumn) - strftime('%s','00:00:00')), 'unixepoch') totaltime from tablename The result time sum will be in format hh:mm:ss.
Oracle 11x Newbie - simple, but sincere...
First, thank you for taking the time to read this, I am fairly well experienced with most versions of MSSQL, but not so much with Oracle and PL SQL. My problem and question are this: I have a SSRS report in MSSQK2k12 that is calling a stored proc on an Oracle 11x db. there are several params passed in that are used in the where clause, I need to add one more param ( a simple Y/N) that will add additional filters to the where clause, effectively saying at the report prompt 'do you want to see all parts? (Y/N). A 'Y' answer will run the proc nearly wide open, including parts that have no inventory, parts on hand, but already sold, parts no longer active. A 'N' response will pass filters that require available inventory, valid current part class, etc. I have attempted a half-dozen seemingly good solutions, to no avail. I have asked an associate (who is well versed in PLSQL) for his advice, his resulting 'DECODE' addition did nothing. I would like to request advice/assistance that does not involve months of study, as I only have a few days to finish. Please note, the original SP was not my work, I have inherited from predecessor would did/could not complete. Stored procedure (Scrubbed) attached CREATE OR REPLACE PROCEDURE ORACLE_PROD.RPT_LIKE_PARTS_TEST ( p_Pos1 IN varchar2 , p_Description IN varchar2 , p_StartPos IN varchar2 , p_StartPosValue IN varchar2 , p_ViewAll IN varchar2 --ADDED to allow filtered return for data , p_recordset OUT SYS_REFCURSOR) AS BEGIN OPEN p_recordset FOR SELECT T1.ITEM , T1.REVISION , T1.DESCRIPTION , T2.CCN , T2.DELETED , T2.OBSOLETED , T2.FINGOOD , T2.ABC , T3.MAS_LOC , T3.LOCATION , (T3.OH_QTY - T3.COM_QTY) - T3.RESV_QTY as Avail_QTY , T1.USER_NUM1 , case when T2.HALT<>' ' then 'Y' else NULL end as Halt , T4.DESCRIPTION as T4_Description , det.OH_QTY as Det_OH_QTY , det.COM_QTY as Det_COM_QTY , DECODE(det.INSP_STAT,'3','Passed Inpection' ,DECODE det.INSP_STAT,'1','Waiting Inspection' ,' ')) as Inspect_Descr , T3.RESV_QTY from ITEM T1 LEFT OUTER JOIN ITEM_CCN T2 ON T1.ITEM=T2.ITEM and T1.REVISION=T2.REVISION LEFT OUTER JOIN ITEM_LOC T3 on T2.CCN=T3.CCN and T2.ITEM=T3.ITEM and T2.REVISION=T3.REVISION LEFT OUTER JOIN HALT T4 on T2.HALT=T4.HALT and T2.CCN=T4.CCN LEFT OUTER JOIN ITEM_DET det on T3.CCN=det.CCN and T3.ITEM=det.ITEM and T3.REVISION=det.REVISION and T3.MAS_LOC=det.MAS_LOC and T3.LOCATION=det.LOCATION where T2.OBSOLETED is null --** all commented parts are attempted adds --&&&and CASE (p_ViewAll) --&&& when 'N' --&&& THEN --T2.HALT = DECODE(T2.HALT,'DSGN', 'XXX',' ','XXX',T2.HALT) -- and --&&& (T2.HALT != 'DSGN' and (((T3.OH_QTY - T3.COM_QTY) - T3.RESV_QTY))> 0 --and T2.HALT <> 'DSGN' and T3.mas_loc <>'99' and T3.mas_loc <>' ' --&&&WHEN 'Y' --&&& THEN and T2.HALT <>'DSGN' --&&&ELSE NULL-- or T3.mas_loc <> '') --&&&END --** /*and T2.HALT = decode(p_ViewAll,'Y', DECODE(T2.HALT,'DSGN', T2.HALT), DECODE(T2.HALT,'DSGN', T2.HALT) --DECODE(T2.HALT,'DSGN', 'XXX',' ','XXX',T2.HALT), --DECODE(T2.HALT,'DSGN', 'XXX', T2.HALT) ) and (p_ViewAll != 'Y' or T3.mas_loc not in ('99',' '))*/ --** AND UPPER(TRIM(T1.ITEM)) LIKE (CASE WHEN LENGTH(TRIM(p_pos1)) > 0 THEN UPPER(TRIM(p_pos1) || '%') ELSE UPPER(TRIM(T1.ITEM))END) AND UPPER(T1.DESCRIPTION) LIKE (CASE WHEN LENGTH(p_Description) > 0 THEN UPPER(('%' || p_Description || '%')) ELSE UPPER(UPPER(T1.DESCRIPTION))END) AND (CASE WHEN TO_NUMBER(NVL(TRIM(p_StartPos),'0')) > 0 THEN SUBSTR(TRIM(T1.ITEM),TO_NUMBER(TRIM(p_StartPos)),NVL(LENGTH(UPPER(TRIM(p_StartPosValue))),'0')) ELSE 'False' END) = (CASE WHEN TO_NUMBER(NVL(TRIM(p_StartPos),'0')) > 0 THEN NVL(UPPER(TRIM(p_StartPosValue)),'') ELSE 'False' END) ORDER BY T1.ITEM , T1.revision desc ; END RPT_LIKE_PARTS_TEST; /
You have to use UNION and not decode. In one side of UNION you have to handle parameter Y with outer join and other will be as you have coded already. OR you need to use if / else of PLSQL since user can pass only one of them as parameter. To be honest, this question is nothing specific to oracle and mere SQL.
so with the union all or union solution probably looks something like this /* Formatted on 7/5/2016 1:50:34 PM (QP5 v5.256.13226.35510) */ SELECT T1.ITEM, T1.REVISION, T1.DESCRIPTION, T2.CCN, T2.DELETED, T2.OBSOLETED, T2.FINGOOD, T2.ABC, T3.MAS_LOC, T3.LOCATION, (T3.OH_QTY - T3.COM_QTY) - T3.RESV_QTY AS Avail_QTY, T1.USER_NUM1, CASE WHEN T2.HALT <> ' ' THEN 'Y' ELSE NULL END AS Halt, T4.DESCRIPTION AS T4_Description, det.OH_QTY AS Det_OH_QTY, det.COM_QTY AS Det_COM_QTY, DECODE (det.INSP_STAT, '3', 'Passed Inpection', DECODE det.INSP_STAT,'1','Waiting Inspection' ,' ')) as Inspect_Descr , T3.RESV_QTY from ITEM T1 LEFT OUTER JOIN ITEM_CCN T2 ON T1.ITEM=T2.ITEM and T1.REVISION=T2.REVISION LEFT OUTER JOIN ITEM_LOC T3 on T2.CCN=T3.CCN and T2.ITEM=T3.ITEM and T2.REVISION=T3.REVISION LEFT OUTER JOIN HALT T4 on T2.HALT=T4.HALT and T2.CCN=T4.CCN LEFT OUTER JOIN ITEM_DET det on T3.CCN=det.CCN and T3.ITEM=det.ITEM and T3.REVISION=det.REVISION and T3.MAS_LOC=det.MAS_LOC and T3.LOCATION=det.LOCATION where T2.OBSOLETED is null and p_ViewAll = 'Y' UNION ALL SELECT T1.ITEM , T1.REVISION , T1.DESCRIPTION , T2.CCN , T2.DELETED , T2.OBSOLETED , T2.FINGOOD , T2.ABC , T3.MAS_LOC , T3.LOCATION , (T3.OH_QTY - T3.COM_QTY) - T3.RESV_QTY as Avail_QTY , T1.USER_NUM1 , case when T2.HALT<>' ' then 'Y' else NULL end as Halt , T4.DESCRIPTION as T4_Description , det.OH_QTY as Det_OH_QTY , det.COM_QTY as Det_COM_QTY , DECODE(det.INSP_STAT,'3','Passed Inpection' ,DECODE det.INSP_STAT,'1','Waiting Inspection' ,' ')) as Inspect_Descr , T3.RESV_QTY from ITEM T1 LEFT OUTER JOIN ITEM_CCN T2 ON T1.ITEM=T2.ITEM and T1.REVISION=T2.REVISION LEFT OUTER JOIN ITEM_LOC T3 on T2.CCN=T3.CCN and T2.ITEM=T3.ITEM and T2.REVISION=T3.REVISION LEFT OUTER JOIN HALT T4 on T2.HALT=T4.HALT and T2.CCN=T4.CCN LEFT OUTER JOIN ITEM_DET det on T3.CCN=det.CCN and T3.ITEM=det.ITEM and T3.REVISION=det.REVISION and T3.MAS_LOC=det.MAS_LOC and T3.LOCATION=det.LOCATION where T2.OBSOLETED is null and p_ViewAll = 'N' and myfilterstuff = 'whatever'
The query performance is very low + correlated subquery
The query's aim is to get reserved rooms status is 3 or going to reserve in 30 to 45 minutes status in 2 or unreserved status in 1. reservation rooms are in RESEENH table and each reservation is in ORD_NOARCHIVE table which has begintime and endtime of reservation. So for each reservation room this query checks whether reservation is available at current time also its checks the meeting room parents and children. if children is reserved then parents are are blocked. it takes 10 secs to fetch first 50 records. with cte as ( SELECT DISTINCT R.syscode, R.behcode, R.syscode AS FK_RESERVATIONUNIT, ( CASE WHEN R.TYPE = 3 THEN '1' WHEN R.TYPE = 1 THEN '2' ELSE NULL END ) AS LOCATION_TYPE, R.sysobjalg AS FK_PROPERTY, MP.syscode AS FK_MEASUREMENTPOINT, MP.fk_plc_occupancy_state AS FK_PLC_OCCUPANCY_STATE, F.syscode AS FK_FLOOR, R.transitiontime, r.type, r.is_compoundreservationunit, r.is_archived, MP.fk_person, os.transitionperiod FROM reseenh R --left outer join ordtrantbl RSS --ON RSS.reservationunisyscode = R.syscode left outer join objond F ON F.syscode = R.fk_floor left outer join pln_measurementpoint MP ON MP.fk_reservationunit = R.syscode AND MP.is_primary_measurement_point = 'T', pln_ordersetting os ) select cte.syscode,cte.behcode,cte.FK_RESERVATIONUNIT, (CASE WHEN O.begindatetime_user IS NULL THEN '1' --GREEN WHEN O.begindatetime_user - (Nvl(cte.transitiontime, ( cte.transitionperiod ))/1440 ) > current_date THEN '2' -- ORANGE WHEN O.begindatetime_user + (Nvl(cte.transitiontime, ( cte.transitionperiod )) /1440 ) > current_date THEN '3' -- RED ELSE '3' END ) AS LOCAVAILABILITY_STATUS_CODE, cte.LOCATION_TYPE, cte.FK_PROPERTY, Coalesce(O.sysmelder, cte.fk_person) AS FK_PERSON, O.syscode AS FK_ORDER, O.ref_bostate_userdefined AS FK_ORDER_STATE_USER, O.fk_bostate AS FK_ORDER_STATE_SYSTEM, FK_MEASUREMENTPOINT,FK_PLC_OCCUPANCY_STATE,FK_FLOOR from cte left outer join ord_noarchive O on O.syscode in ( SELECT MAX(ord.syscode) KEEP (DENSE_RANK FIRST ORDER BY ord.begindatetime_user) OVER (PARTITION BY ord.sysreseenh ) FROM ord_noarchive ORD WHERE ( ( ( current_date >= ( ORD.begindatetime_user - ( Nvl(cte.transitiontime, ( cte.transitionperiod ))/1440) ) AND ( current_date - ( Nvl(cte.transitiontime, (cte.transitionperiod )) / 1440 ) ) <=ORD.enddatetime_user ) OR ( ( current_date + ( ( CASE WHEN ( cte.TYPE = 1 ) THEN 30 ELSE 45 END ) / 1440 ) ) >= ( ORD.begindatetime_user - (Nvl(cte.transitiontime, ( cte.transitionperiod))/1440 ) ) AND ( current_date - ( Nvl(cte.transitiontime, ( cte.transitionperiod )) / 1440 ) ) < ORD.enddatetime_user ) ) AND ORD.sysreseenh IN ( SELECT fk_reservationunit_parent FROM pln_reservationunit_rut WHERE fk_reservationunit_child IN ( SELECT fk_reservationunit_child FROM pln_reservationunit_rut WHERE cte.is_compoundreservationunit = 'T' AND fk_reservationunit_parent = cte.syscode) UNION SELECT cte.syscode FROM dual UNION SELECT CASE WHEN cte.is_compoundreservationunit = 'T' THEN fk_reservationunit_child ELSE fk_reservationunit_parent END FROM pln_reservationunit_rut WHERE ( cte.is_compoundreservationunit = 'T' AND fk_reservationunit_parent = cte.syscode ) OR ( cte.is_compoundreservationunit = 'F' AND fk_reservationunit_child = cte.syscode )) AND ORD.fk_bostate IN ( SELECT syscode FROM pln_bostate WHERE pnname IN ( 'Requested', 'Made', 'AdministrativelyCompleted' ) AND fk_bodefinition = ref_bodefinition) AND ORD.sysreseenh = O.sysreseenh )) WHERE cte.is_archived = 'F' AND cte.TYPE IN ( 1, 3 ) AND cte.fk_floor=495
No time to analyze the details of a very complex query, but my overall sense is that you are trying to do too many things at once. Separate the tasks. Check on room availability in one query, and check on the children/parent thing in a separate query. Also, you could analyze the execution plan for the query and see what it bogging it down. My suspicion (again without time to really try to understand your query) is that at some point the mixing of tasks is translating into a many-to-many relationship where you have an intermediate result that is a cross product of rows between some of the tables in your query.
How to Get Month Text In Arabic?
I have This below query its working fine for Month Text in English but we need Month Text in Arabic How we do??I have Sql Server 2008R2.I have check using FORMAT function but its not work in 2008r2 edition. DECLARE #tempdate TABLE ( pricedate DATETIME NOT NULL, priceid INT NOT NULL ) INSERT INTO #tempdate (pricedate, priceid) SELECT pricelist_date, pricelist_id FROM vw_lu_region_and_date_list WHERE price_status = '3' AND region_id = '1' AND saletype = '2' ORDER BY pricelist_date DESC; WITH numbered AS (SELECT *, Row_number() OVER ( partition BY Dateadd(month, Datediff(month, 0, pricedate), 0 ) ORDER BY pricedate DESC) AS rn FROM #tempdate) SELECT RIGHT(CONVERT(NVARCHAR(20), pricedate, 106), 8) AS PRICELIST_DATE, priceid AS PRICELIST_ID FROM numbered WHERE rn = 1 ORDER BY priceid DESC I have get result from above query like Apr 2013 Mar 2013 but we need like Apr and Mar in Arabic????
I also suggest to store as normal date and you can probably convert in your client application rather than in SQL. In the organization I once worked for the previous developer designed a SQL CLR function to convert dates into Hebrew dates and return in Hebrew. But You Can Use This : CREATE FUNCTION dbo.fnTranslateMonthNameToArabic (#date as datetime) RETURNS nvarchar(50) AS BEGIN DECLARE #result AS nvarchar(50); IF MONTH(#date) = 1 SET #result = (SELECT CONVERT(nvarchar(2), DAY(#date)) + N' ' + N'يناير' + N' ' + CONVERT(nvarchar(4), YEAR(#date))); IF MONTH(#date) = 2 SET #result = N'and so on ...'; RETURN #result; END Go -- Test SELECT dbo.fnTranslateMonthNameToArabic({d N'2012-01-16'}) AS Arabic At Last Please Take a Look at Arabic Language Support in SQL Server
Getting next date based on start date in Oracle
I have a scenario where, I have to get the receiving dates based on the delivery dates in the system. The sample system I am referring to is a shopping cart and for every order, the receiving date can be any of the 5 dates. For Example, SHOP_ID CITY ST MON TUE WED THU FRI 0566567890823 CARLSBAD CA M H 1950567890821 SAN DIEGO CA M H 2171567890842 ESCONDIDO CA T H 1028567890864 CALEXICO CA T H 1950567890849 SAN DIEGO CA F 2171567890878 ESCONDIDO CA W F 1274567890882 CHULA VISTA CA T H 2414567890891 EL CAJON CA M 0634567890804 ESCONDIDO CA M H 1274567890845 CHULA VISTA CA W F 0634567890828 ESCONDIDO CA F 2414567890897 EL CAJON CA W F So for shop '0566567890823', if delivery date is tomorrow (21st March), the pickup date is the very nearest Monday (24th March), as the shop accepts the orders on Monday and Thursday. similarly, if delivery date is Tuesday (25th March), the shop accepts the orders on Thursday (27th March). Can someone please help me with a query which can give me the possible pickup date based on the shop id and the delivery date Below are the create and insert scripts for the table. CREATE TABLE "DELIVERY_DETAILS" ( "SHOP_ID" VARCHAR2(15) NOT NULL ENABLE, "CITY" VARCHAR2(15), "STATE" VARCHAR2(15), "MON" CHAR(1), "TUE" CHAR(1), "WED" CHAR(1), "THU" CHAR(1), "FRI" CHAR(1) ); INSERT INTO DELIVERY_DETAILS VALUES ('0566567890823', 'CARLSBAD', 'CA', 'M', '', '', 'H', ''); INSERT INTO DELIVERY_DETAILS VALUES ('1950567890821', 'SAN DIEGO', 'CA', 'M', '', '', 'H', ''); INSERT INTO DELIVERY_DETAILS VALUES ('2171567890842', 'ESCONO', 'CA', '', 'T', '','H', ''); INSERT INTO DELIVERY_DETAILS VALUES ('1028567890864', 'CALEXICO', 'CA', '', 'T', '', 'H', ''); INSERT INTO DELIVERY_DETAILS VALUES ('1950567890849', 'SAN DIEGO', 'CA', '', '', '', '', 'F'); INSERT INTO DELIVERY_DETAILS VALUES ('2171567890878', 'ESCONDIDO', 'CA', '', '', 'W', '', 'F'); INSERT INTO DELIVERY_DETAILS VALUES ('1274567890882', 'CHULA VISTA', 'CA', '','T', '','H', ''); INSERT INTO DELIVERY_DETAILS VALUES ('2414567890891', 'EL CAJON', 'CA', 'M', '', '', '', ''); INSERT INTO DELIVERY_DETAILS VALUES ('0634567890804', 'ESCONDIDO', 'CA', 'M', '', '', 'H', ''); INSERT INTO DELIVERY_DETAILS VALUES ('1274567890845', 'CHULA VISTA', 'CA', '', '', 'W', '', 'F'); INSERT INTO DELIVERY_DETAILS VALUES ('0634567890828', 'ESCONDIDO', 'CA', '', '', '', '', 'F'); INSERT INTO DELIVERY_DETAILS VALUES ('2414567890897', 'EL CAJON', 'CA', '', '', 'W', '', 'F'); The input is delivery date which is system driven (can be a system date as well) and output is the possible pickup date of the shop. Similar to the above example, if it is 'M', the pickup would be nearest next Monday Thanks a lot
I would unpivot the data first. select * from ( select * from delivery_details where shop_id = '2171567890878' ) unpivot( ind for week_day in ( mon as 'monday', tue as 'thursday', wed as 'wednesday', thu as 'thursday', fri as 'friday' ) ); | SHOP_ID | CITY | STATE | WEEK_DAY | IND | |---------------|-----------|-------|-----------|-----| | 2171567890878 | ESCONDIDO | CA | wednesday | W | | 2171567890878 | ESCONDIDO | CA | friday | F | Once you have this, use NEXT_DAY to get the next pickup date. If your delivery day equals the pickup day, next_day function will give you one week later date. If you don't want that to happen, use case statement to return the delivery_date. select shop_id, city, state, case when to_char(date'2014-03-21','fmday') = week_day then date'2014-03-21' else next_day(date'2014-03-21',week_day) end pickup_date from ( select * from ( select * from delivery_details where shop_id = '2171567890878' ) unpivot( ind for week_day in ( mon as 'monday', tue as 'thursday', wed as 'wednesday', thu as 'thursday', fri as 'friday' ) ) ); | SHOP_ID | CITY | STATE | PICKUP_DATE | |---------------|-----------|-------|------------------------------| | 2171567890878 | ESCONDIDO | CA | March, 26 2014 00:00:00+0000 | | 2171567890878 | ESCONDIDO | CA | March, 21 2014 00:00:00+0000 | Then just apply MIN to get the nearest date. select min( case when to_char(date'2014-03-21','fmday') = week_day then date'2014-03-21' else next_day(date'2014-03-21',week_day) end ) pickup_date from ( select * from ( select * from delivery_details where shop_id = '2171567890878' ) unpivot( ind for week_day in ( mon as 'monday', tue as 'thursday', wed as 'wednesday', thu as 'thursday', fri as 'friday' ) ) ); | PICKUP_DATE | |------------------------------| | March, 21 2014 00:00:00+0000 | SQLFiddle
This is not a proper solution. But you can think of these functions and check. SELECT T1.*, DELIVERY, LEAST ( NVL ( ABS ( M - DELIVERY ), 8 ), NVL ( ABS ( T - DELIVERY ), 8 ), NVL ( ABS ( W - DELIVERY ), 8 ), NVL ( ABS ( H - DELIVERY ), 8 ), NVL ( ABS ( F - DELIVERY ), 8 ) ) LEASTVAL, FROM (SELECT SHOP_ID, CASE WHEN MON IS NOT NULL THEN NEXT_DAY ( TRUNC ( SYSDATE ), 'MONDAY' ) ELSE NULL END AS M, CASE WHEN TUE IS NOT NULL THEN NEXT_DAY ( TRUNC ( SYSDATE ), 'TUESDAY' ) ELSE NULL END AS T, CASE WHEN WED IS NOT NULL THEN NEXT_DAY ( TRUNC ( SYSDATE ), 'WEDNESDAY' ) ELSE NULL END AS W, CASE WHEN THU IS NOT NULL THEN NEXT_DAY ( TRUNC ( SYSDATE ), 'THURSDAY' ) ELSE NULL END AS H, CASE WHEN FRI IS NOT NULL THEN NEXT_DAY ( TRUNC ( SYSDATE ), 'FRIDAY' ) ELSE NULL END AS F FROM DELIVERY_DETAILS WHERE SHOP_ID = 0566567890823 AND COALESCE ( MON, TUE, WED, THU, FRI ) IS NOT NULL) T1, (SELECT TO_DATE ( '21-MAR-2014', 'DD-MON-YYYY' ) AS DELIVERY FROM DUAL) T2;