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;

Resources