Oracle - missing window specification for this function - oracle

I have inherited a oracle database and being used to MySQL I am struggling to get the data I need.
I am trying to get records from TTDINV700732 and TTCCOM001732 where the max(date) in TTDINV700732 is GTEQ one year ago and where there are records in the joined table TTDINV150732 where the date is GTEQ today.
I get the error
[99999][30484] ORA-30484: missing window specification for this function
Here is my SQL
SELECT
first_value(trim("TTDINV700732"."T$ITEM")) AS "item",
first_value("TTDINV700732"."T$CWAR") AS "whse",
max("TTDINV700732"."T$TRDT") AS "date",
first_value("TTCCOM001732"."T$NAMB") AS "business"
FROM "DB"."TTDINV700732" "TTDINV700732"
LEFT OUTER JOIN "DB"."TTIITM001732" "TTIITM001732" ON "TTDINV700732"."T$ITEM"="TTIITM001732"."T$ITEM"
LEFT OUTER JOIN "DB"."TTCCOM001732" "TTCCOM001732" ON "TTIITM001732"."T$CPLB"="TTCCOM001732"."T$EMNO"
LEFT OUTER JOIN "DB"."TTDINV150732" "TTDINV150732" ON "TTDINV150732"."T$ITEM"="TTDINV700732"."T$ITEM"
where "TTDINV700732"."T$TRDT" <= to_date('12 Oct 2016', 'DD MON YYYY')
and "TTDINV700732"."T$QUAN" < 0
and "TTDINV150732"."T$DATE" >= to_date('12 Oct 2017','DD MON YYYY')
group by "TTDINV700732"."T$ITEM", "TTDINV700732"."T$CWAR"

where the max(date) in TTDINV700732 is GTEQ one year ago (from today)
If you filter that table for <= to_date('12 Oct 2016', 'DD MON YYYY') then no maximum can be greater than the date you have specified, is that intentional/correct? OR, do you require a subquery to get the MAX() dates then use HAVING MAX(T$TRDT) <= to_date('12 Oct 2016', 'DD MON YYYY') ??
...joined table TTDINV150732 where the date is GTEQ today
Should this be equal to today, or greater than and equal ??
Would something like this work?
SELECT
t700732.t$item AS item
, t700732.t$cwar AS whse
, t700732.mx_date AS mx_date
, ttccom001732.t$namb AS business
FROM (
SELECT ttdinv700732.t$item , ttdinv700732.t$cwar, MAX(ttdinv700732.t$trdt) mx_date
FROM db.ttdinv700732
WHERE ttdinv700732.t$quan < 0
GROUP BY ttdinv700732.t$item , ttdinv700732.t$cwar
HAVING MAX(ttdinv700732.t$trdt) <= To_date('12 Oct 2016', 'DD MON YYYY')
) t700732
INNER JOIN db.ttdinv150732 ON t700732.t$item = ttdinv150732.t$item
LEFT OUTER JOIN db.ttiitm001732 ON ttdinv700732.t$item = ttiitm001732.t$item
LEFT OUTER JOIN db.ttccom001732 ON ttiitm001732.t$cplb = ttccom001732.t$emno
where ttdinv150732.t$date >= To_date('12 Oct 2017', 'DD MON YYYY')
You may find it easier to solve it like it was MySQL instead of attempting features of Oracle that you are not familiar with yet.

Related

Oracle to_char in query is not working

Im trying to run this below query but its seems to be error
For those data types are varchar
Query
select *
from RP_REPORT_TEMP
where to_char(START_DATE,'FM DD YYYY HH24:MI:SS AM')
>= 'May 01 2016 00:00:00'
and to_char(END_DATE,'FM DD YYYY HH24:MI:SS PM')
<= 'May 31 2016 11:59:00'
and lower(rid) like '%a001%'
order by CAST(cid as INTEGER) asc
Table
|RID |START_DATE |END_DATE |
|--------------------|-------------------------- |-----------------------------|
|A001 |May 1 2016 12:00:00:000AM |May 31 2016 12:00:00:000PM |
|A001 |May 1 2016 12:00:00:000AM |May 31 2016 12:00:00:000PM |
|A001 |May 1 2016 12:00:00:000AM |May 31 2016 12:00:00:000PM |
While i tried to execute this query. Query return some error. How can i fix this ?
Error
SQL Error [1722] [42000]: ORA-01722: invalid number
java.sql.SQLSyntaxErrorException: ORA-01722: invalid number
Why don't you use TO_DATE() on the date instead?
select * from RP_REPORT_TEMP
where START_DATE >= to_date('May 01 2016 12:00:00 AM','MON DD YYYY HH:MI:SS AM')
and END_DATE <= to_date('May 31 2016 11:59:00 AM','MON DD YYYY HH24:MI:SS AM')
and lower(rid) like '%a001%'
Assuming that START_DATE and END_DATE are actually dates, I can spot two main issues in your code:
Casting every row to string is slow and also prevents Oracle from using indexes (unless you have a carefully built function-based index).
Lexicographical sort (aka "A to Z") does not render meaningful results with dates with "May 1". Just think of what sense this list has: Apr, Aug, Dec, Feb, Jan, Jul, Jun, Mar, May, Nov, Oct, Sep
My suggestions are:
Avoid converting dates to string, save for display purposes
Use a more solid format when you have to convert from string to date
As a result:
select *
from RP_REPORT_TEMP
where START_DATE
>= TO_DATE('2016-05-01 00:00:00', 'YYYY-MM-DD HH24:MI:SS')
and END_DATE
<= TO_DATE('2016-05-31 11:59:00', 'YYYY-MM-DD HH24:MI:SS')
and lower(rid) like '%a001%'
order by CAST(cid as INTEGER) asc
P.S. START_DATE and END_DATE were not dates after all
Try this..
select *
from RP_REPORT_TEMP
where TO_date(START_DATE,'MON DD YYYY HH:MI:SS AM')
>= to_Date('May 01 2016 12:00:00 AM' ,'MON DD YYYY HH:MI:SS AM')
and TO_DATE(END_DATE,'MON DD YYYY HH:MI:SS PM')
<= TO_DATE('May 31 2016 11:59:00 AM' ,'MON DD YYYY HH:MI:SS PM')
and lower(rid) like '%a001%'
order by CAST(cid as INTEGER) asc
select *
from RP_REPORT_TEMP
where TO_date(START_DATE,'MON DD YYYY HH24:MI:SS')
>= to_Date('May 01 2016 12:00:00' ,'MON DD YYYY HH24:MI:SS')
and TO_DATE(END_DATE,'MON DD YYYY HH24:MI:SS')
<= TO_DATE('May 31 2016 11:59:00' ,'MON DD YYYY HH24:MI:SS')
and lower(rid) like '%a001%'
order by CAST(cid as INTEGER) asc
This is what your query should look like:
select *
from rp_report_temp
where to_date(start_date,'FM Mon DD YYYY HH:MI:SS"FMMon DD YYYY HH:MI:SS":000"AM', 'nls_date_language = english')
>= to_date('01/05/2016 00:00:00', 'dd/mm/yyyy hh24:mi:ss')
and to_date(end_date,'FM Mon DD YYYY HH:MI:SS":000"AM', 'nls_date_language = english')
<= to_date('31/05/2016 23:59:59', 'dd/mm/yyyy hh24:mi:ss')
and lower(rid) like '%a001%'
order by cast(cid as integer) asc;
Here, I have converted your start and end date columns into a date, based on the fact that a sample string in that column looks like "May 1 2016 12:00:00:000AM" - there's an extra ":000" after the seconds; I'm assuming this is always ":000".
Note how I've made your code nls_date_language parameter independent, by specifically setting that value within the to_date(). This means that if someone else's client has that set to something that's not English, the sql statement will still work for them.
You'll note that I didn't need to do that for the values you're testing, since I changed the format of the string to something that used numbers to represent the months.
You have some fundamental data modelling issues here too - by storing everything as varchar2 you have made a rod for your own back - you've lost all the validation available (what happens if someone puts a string of Feb 30 2015 39:99:99 AM in that column? AWOOGA, AWOOGA, error!). You've made your queries have to work harder (now we've got functions all over the place trying to convert data to the correct datatype).
You should store data in the correct datatype. Dates should be stored as DATE, Timestamps as TIMESTAMP, numbers as NUMBER (with or without specific precision and scale), etc etc.
If your data was stored correctly, then your query would be:
select *
from rp_report_temp
where start_date >= to_date('01/05/2016 00:00:00', 'dd/mm/yyyy hh24:mi:ss')
and end_date <= to_date('31/05/2016 23:59:59', 'dd/mm/yyyy hh24:mi:ss')
and lower(rid) like '%a001%'
order by cid asc;

Excluding rows from outer join

I am trying to extract rows from a table to gain the start and end time for events, these are held in a one to many table relationship so that for each instanceid in the master table you can have a number of entryids in the child. I have successfully written the below query that extracts the required data converting epoch timestamps, but am getting rows with NULL values. I can see that to exclude these I need to only select rows from table_a where the status value reflect 1 or 6, but am not sure of syntax for achieving this, I have tried combos of bold highlighted line below to no avail.
SELECT a.summary
to_char(date '1970-01-01' + b.create_date/86400, 'DD Mon YYYY HH24:MI:SS') as start_date,
to_char(date '1970-01-01' + c.create_date/86400, 'DD Mon YYYY HH24:MI:SS') as completed_date,
to_char (TRUNC (SYSDATE) + NUMTODSINTERVAL ((c.create_date - b.create_date), 'second'), 'hh24:mi:ss') as Elapse_Time,
a.status
FROM o2_hpov_casecreation a
LEFT OUTER JOIN o2_hpov_casecreation_audit b
ON (a.instanceid = c.entryid
AND B.action= 'Queueing Simulation phase on SYS:Action')
LEFT OUTER JOIN o2_hpov_casecreation_audit c
ON (a.instanceid = c.entryid
AND c.action = 'Notifications completed')
AND a.status IN (2,6)
You need to add your filter criteria to the where clause
below is a corrected version of your query
SELECT a.summary
to_char(date '1970-01-01' + b.create_date/86400, 'DD Mon YYYY HH24:MI:SS') as start_date,
to_char(date '1970-01-01' + c.create_date/86400, 'DD Mon YYYY HH24:MI:SS') as completed_date,
to_char (TRUNC (SYSDATE) + NUMTODSINTERVAL ((c.create_date - b.create_date), 'second'), 'hh24:mi:ss') as Elapse_Time,
a.status
FROM o2_hpov_casecreation a
LEFT OUTER JOIN o2_hpov_casecreation_audit b
ON (a.instanceid = c.entryid
AND B.action= 'Queueing Simulation phase on SYS:Action')
LEFT OUTER JOIN o2_hpov_casecreation_audit c
ON (a.instanceid = c.entryid
AND c.action = 'Notifications completed')
WHERE a.status IN (2,6)

Performance Tuning in Oracle for dynamic date join

I have a scenario where in I have to aggregate data for a dynamic 24 hour period.
For eg: If a user selects the FROM date as Jan 05 2016 8:00 AM and TO date as Jan 10 2016 2:00 AM data in the output should be aggregated from Jan 05 2016 8:00 AM to Jan 06 2016 7:59 AM as 1 day (Jan 05 2016).
Jan 5 2016 - Jan 5 2016 8:00 AM to Jan 6 2016 7:59 AM
Jan 6 2016 - Jan 6 2016 8:00 AM to Jan 7 2016 7:59 AM
Jan 7 2016 - Jan 7 2016 8:00 AM to Jan 8 2016 7:59 AM
Jan 8 2016 - Jan 8 2016 8:00 AM to Jan 9 2016 7:59 AM
Jan 9 2016 - Jan 9 2016 8:00 AM to Jan 10 2016 2:00 AM
To achieve this, I subtracted 8 hours from the date column in the fact table and joined it to the Date Dimension. The query looks like this:
SELECT D.DAY_FMT,SUM(F.MEASURE) from FACT F
INNER JOIN DATES D ON
to_number(to_char((F.DATESTIME - 0.3333333),'YYYYMMDD')) = D.DATEID
WHERE F.DATESTIME between to_timestamp ('05-Jan-16 08.00.00.000000000 AM')
and to_timestamp ('10-Jan-16 02.00.00.000000000 AM')
GROUP BY D.DAY_FMT
Note 1: If the From Time is 06:00 AM then we would be subtracting 0.25 (days) instead of 0.3333333 (days)
Note 2: The Fact table has billions of rows.
Is there any way to improve the performance of the above query?
In Oracle the date and the time are stored together. You don't need to join on equality, and you don't need to wrap the date within any functions. (And why timestamps?) Having all the computations (if any are even needed) on the "right hand side" of conditions means the computations are done just once, the same for every row, instead of separately for each row.
select f.day_fmt, sum(f.measure) as some_col_name
from fact f inner join dates d
on f.datestime >= to_date('05-Jan-16 08:00:00 AM', 'dd-Mon-yy hh:mi:ss AM')
and f.datestime < to_date('10-Jan-16 02:00:00 AM', 'dd-Mon-yy hh:mi:ss AM')
group by day_fmt;
Edit: Based on further clarification from OP - suppose the data is in table "fact" - with columns day_fmt, measure, and datestime. The assignment is to aggregate (sum) measure, grouped by day_fmt and also grouped by 24-hour intervals, starting from a date-time chosen by the user and ending with a date-time chosen by the user. Solution below.
with user_input (sd, ed) as (
select to_date('05-Jan-16 08:00:00 AM', 'dd-Mon-yy hh:mi:ss AM'),
to_date('10-Jan-16 02:00:00 AM', 'dd-Mon-yy hh:mi:ss AM') from dual
),
prep (dt) as (
select (select sd from user_input) + level - 1 from dual
connect by level < (select ed - sd from user_input) + 1
union
select ed from user_input
),
dates (from_date, to_date) as (
select dt, lead(dt) over (order by dt) from prep
)
select f.day_fmt, d.from_datetime, d.to_datetime, sum(f.measure) as some_column_name
from fact f inner join dates d
on f.datestime >= d.from_datetime and f.datestime < d.to_datetime
where to_datetime is not null
group by f.day_fmt, d.from_datetime, f.to_datetime
order by f.day_fmt, d.from_datetime;
By not using function calls wrapped around f.datestime, you can take advantage of an index defined on this column of the "fact" table (an index you already have or one you can create now, to help speed up your queries).

Get first date of month in oracle

I want to get the distinct months between start and end date. The selected month date would be the first date of the corresponding month. For example, my start date is 01/30/2015 00:00:00 & end date is 11/30/2015 23:59:59
Query I created as :
with data1 as(
select to_date('01/30/2015 00:00:00','MM/DD/YYYY HH24:MI:SS')+level-1 dt
from dual
connect by level <= to_date('11/30/2015 23:59:59','MM/DD/YYYY HH24:MI:SS')-to_date('01/30/2015 00:00:00','MM/DD/YYYY HH24:MI:SS')+1)
select distinct trunc(dt,'MM') as date1
from data1
where dt between to_date('01/30/2015 00:00:00','MM/DD/YYYY HH24:MI:SS') and to_date('11/30/2015 23:59:59','MM/DD/YYYY HH24:MI:SS')
and trunc(dt,'MM') <= to_date('11/30/2015 23:59:59','MM/DD/YYYY HH24:MI:SS')
order by trunc(dt,'MM')
Output:
01/01/2015 00:00:00 ,
02/01/2015 00:00:00 ,
03/01/2015 00:00:00 ,
04/01/2015 00:00:00 ,
05/01/2015 00:00:00 ,
06/01/2015 00:00:00 ,
07/01/2015 00:00:00 ,
08/01/2015 00:00:00 ,
09/01/2015 00:00:00 ,
10/01/2015 00:00:00 ,
11/01/2015 00:00:00
This query result in a correct output, but I have a doubt that the above query will run in all versions of oracle database without any issue. Please give me instructions.
Your query will work. But using ADD_MONTHS allows for the same results with much less work in a more direct way.
select trunc(add_months(date '2015-01-30', level - 1), 'MONTH') as THE_MONTH
from dual
connect by trunc(add_months(date '2015-01-30', level - 1), 'MONTH')
<= date '2015-11-30'
order by THE_MONTH

How to Sum the Values from current date to previous year in oracle

Can any body help me to solve this:
Value Date
1000 01-jan-12
............
1000 01-apr-13
My Aim is to calculate the sum of marks which secured from current month and year APRIL-13 to Previous one year from Current Month and Year.
your example data shows more that one year from apr 2013.
assuming you wanted to go back to apr-2012
select sum(value)
from your_tab
where date >= add_months(trunc(sysdate, 'mm', -12) -- from 1st apr 2012
and date < trunc(sydate, 'mm');-- anytime up to the end of mar 2013
if you wanted to go back to jan of the prior year, then
select sum(value)
from your_tab
where date >= trunc(add_months(trunc(sysdate, 'mm', -12), 'yy') -- from 1st jan 2012
and date < add_months(trunc(sydate, 'mm'), 1); -- anytime up to the end of apr 2013

Resources