select next record date minus 1 based on the logic - oracle

I want to achieve the following output through sql query
Below is the data in the oracle table
date 1 date 2 amt1 amt2
1/1/2012 12/31/2012 100 100
1/1/2013 11/31/2013 100 100
1/1/2014 9/31/2014 50 100
1/1/2015 12/31/2015 20 100
Desired output I need:
date 1 date 2 amt1 amt2
1/1/2012 12/31/2013 100 100
1/1/2014 12/31/2014 50 100
1/1/2015 12/31/9999 20 100
The logic to get the output would be if the amounts are same for multiple records then a single record should exist in the output with the earliest date as date1 . date 2 of the record written to the output should be next record effective date minus 1 , and if there is no next record found ,the date 2 should be defaulted to 31-dec-9999
(Note:whenever there is a change in amt1 or amt 2 between 2 records, those should be treated as separate records and if amts are same for all records then a single record should exist in the output )
Please let me know how to achieve this output through sql query

This solution uses a sub-query to aggregate a single row for each permutation of AMT1 and AMt2. Then it applies an analytic LEAD() function to get the next DATE1 and manipulates it according to the specification.
with yt as (
select amt1
, amt2
, min(date1) as date1
, max(date2) as date2
from your_table
group by amt1
, amt2
)
select yt.date1
, nvl(lead(yt.date1) over (order by yt.date1)-1, date '9999-12-31') as date2
, amt1
, amt2
from yt
order by yt.date1
/
By the way I had to correct your data (bad dates) when I used it in the inevitable SQL Fiddle; find it here.

Related

I have date time and I want to count but only by date in Oracle, now I have dates but several times

I have date time field, lets call it timestamp_1 and I want to display how many rows I have for each date. So I need to have i.e.
date count
2017-11-20 4
2017-12-01 10
2017-12-10 15
using such sql
select cast(timestamp_1 as date), count(*)
from table
group by cast(timestamp_1 as date)
order by cast(timestamp_1 as date) desc
I got
date count
2017-11-20 1
2017-11-20 1
2017-11-20 2
2017-12-01 6
2017-12-01 4
2017-12-10 3
2017-12-10 6
2017-12-10 6
what am I doing wrong?
I guess you want to count the number of rows per day? then you can use
TRUNC ( date [, format ] ) in group by
i.e
TRUNC(timestamp_1 , 'DD')
The simplest option would be this, I presume:
select trunc(timestamp_1), count(*)
from table
group by trunc(timestamp_1)
order by 1;
Use to_char for date column
Select to_char(date_column,'DD-MON-YYYY') from some_table

How to group by month including all months?

I group my table by months
SELECT TO_CHAR (created, 'YYYY-MM') AS operation, COUNT (id)
FROM user_info
WHERE created IS NOT NULL
GROUP BY ROLLUP (TO_CHAR (created, 'YYYY-MM'))
2015-04 1
2015-06 10
2015-08 22
2015-09 8
2015-10 13
2015-12 5
2016-01 25
2016-02 37
2016-03 24
2016-04 1
2016-05 1
2016-06 2
2016-08 2
2016-09 7
2016-10 103
2016-11 5
2016-12 2
2017-04 14
2017-05 2
284
But the records don't cover all the months.
I would like the output to include all the months, with the missing ones displayed in the output with a default value:
2017-01 ...
2017-02 ...
2017-03 ZERO
2017-04 ZERO
2017-05 ...
Oracle has a good array of date manipulation functions. The two pertinent ones for this problem are
MONTHS_BETWEEN() which calculates the number of months between two dates
ADD_MONTHS() which increments a date by the given number of months
We can combine these functions to generate a table of all the months spanned by your table's records. Then we use an outer join to conditionally join records from USER_INFO to that calendar. When no records match count(id) will be zero.
with cte as (
select max(trunc(created, 'MM')) as max_dt
, min(trunc(created, 'MM')) as min_dt
from user_info
)
, cal as (
select add_months(min_dt, (level-1)) as mth
from cte
connect by level <= months_between(max_dt, min_dt) + 1
)
select to_char(cal.mth, 'YYYY-MM') as operation
, count(id)
from cal
left outer join user_info
on trunc(user_info.created, 'mm') = cal.mth
group by rollup (cal.mth)
order by 1
/

how combine multiple rows into a single row in Oracle?

How can i do below in oracle?
input
id units unit_description
12 20 kWh
12 50 kWh
12 100 days
15 80 kWh
I want merged in column 2 and 3 based on column 1 into one single row. And the result should be like
output:
id | unit details
12 70 KWh , 100 days
15 80 KWh
Check the below query. Mostly it should work in your case. It may not execute at once, modify as per your requirement.
SELECT id,
LISTAGG (unit || ' ' || unit_description, ', ')
WITHIN GROUP (ORDER BY unit, unit_description)
FROM ( SELECT id, unit_description, SUM (unit) AS unit
FROM table1
GROUP BY id, unit_description)
GROUP BY id;

One column calculate multiple output

I have show the total product sale on the basis YTD (Year to Date), QTD(Quarter to Date) and MTD (Month to Date). The thing is I have to show only one from those. Only one output can be seen on the basis of selection i.e. like we have radio buttons to select one from many. Here also a input is given to select and on the basis of that input the output is generated. The input can be any YTD,QTD or MTD. The output is generated on the basis of input. I don't how to calculate a column output where the input can be vary.
I have a Product Table-
Product_ID Product_name Price
1 Mobile 200
2 T.V. 400
3 Mixer 300
I have a Sales table like this-
Product_ID Sales_Date Quantity
1 01-01-2015 30
2 03-01-2015 40
3 06-02-2015 10
1 22-03-2015 30
2 09-04-2015 10
3 21-05-2015 40
1 04-06-2015 40
2 29-07-2015 30
1 31-08-2015 30
3 14-09-2015 30
And my ouput column contains 3 columns that are-
Product_id, Product_Name and Total_Amount.
The column Total_Amount(quantity*price) have to calculate sale on the basis of input given by user i.e.,
IF it is YTD then it should calculate the total sale from Starting Date of Year ( 01-01-2015) to the current_date(sysdate),
IF it is QTD then in which quarter the current date is falling i.e if current month is september then from 1 July to current_date(sysdate),
IF it is MTD then in which month the current date is falling to the current_date(sysdate).
Can anyone help. Thanks!!!
-- step 1
create or replace view my_admin
as
select 'YTD' element, product_id, sum(quantity) sum_quantity
from sales
where Sales_date between trunc(sysdate,'Y') and sysdate
group by product_id
union
select 'QTD', product_id, sum(quantity) sum_quantity
from sales
where Sales_date between trunc(sysdate,'Q') and sysdate
group by product_id
union
select 'MTD', product_id, sum(quantity) sum_quantity
from sales
where Sales_date between trunc(sysdate,'MM') and sysdate
group by product_id
-- step 2
select element, p.product_name, (sum_quantity * p.PRICE) agregate
from my_admin a
inner join products p on a.product_id = p.product_id
where element = (:input)
My presumption is that you have 3 radio buttons(variables :YTD,:QTD,:MTD in my example) where just one value at a time can be picked by the user the rest will be null.
You can use a something like this to get what you want:
select SUM(a.QTY*B.PRICE) from PRODUCTS a
inner join SALES B on a.PRODUCT_ID=B.PRODUCT_ID
where
(:YTD is null or B.SALES_DATE between '01-JAN-15' and sysdate)
and
(:QTD is null or TO_CHAR(B.SALES_DATE, 'YYYY-Q')=TO_CHAR(sysdate, 'YYYY-Q'))
and
(:MTD is null or TO_CHAR(B.SALES_DATE, 'MM')=TO_CHAR(sysdate, 'MM'));
You can test it here sqlfiddle

How to find the difference between two timestamp column

I have table name Record which has the following columns, Empid in number column, dat in timestamp
Which has the following values
empid dat
====== ====
101 4/9/2012 9:48:54 AM
101 4/9/2012 9:36:28 AM
101 4/9/2012 6:16:28 PM
101 4/10/2012 9:33:48 AM
101 4/10/2012 12:36:28 PM
101 4/10/2012 8:36:12 PM
101 4/11/2012 9:36:28 AM
101 4/11/2012 4:36:22 PM
Here I need to display the following columns,
empid,min(dat) as start,max(dat) as end and difference(max(dat)-min(dat) for each day
Here 3 different days are exists so It should return 3 records with the above mentioned columns.
Please give some ways to get this.
Simply subtract them: max(dat) - min(dat)
SELECT empid,
min(dat) as strt,
max(dat) as end,
max(dat) - min(dat) as diff
FROM the_table
GROUP BY empid;
If you want to group by the day instead of the empid, use this one:
select trunc(dat),
min(dat) as strt,
max(dat) as end,
max(dat) - min(dat) as diff
from the_table
group by trunc(dat)
Date arithmetic is pretty straightforward in Oracle: the difference betwwen two dates is returned as the number of days. Values of less than a day are returned as *decimals". That is, 75 minutes is 1.25 hours not 1.15. If you want it as hours and minutes you need to work with an interval.
The inner query calculates the difference between the minimum and maximum data for each employee for each day, and converts it to a DAY interval. The outer query extracts the HOUR and MINUTES from that interval.
select empid
, tday
, sdt
, edt
, extract(hour from diff) diff_hours
, extract (minute from diff) diff_minutes
from (
select empid
, trunc(dat) tday
, min(dat) sdt
, max(dat) edt
, numtodsinterval(max(dat) - min(dat), 'DAY') diff
from t42
group by empid, trunc(dat)
)

Resources