select records with a 6 month interval - sql

I want to select with an oracle sql statement the records with a 6 month time interval.
Example
01/06/2011 AMOUNT
01/12/2011 AMOUNT
01/06/2012 AMOUNT
01/12/2012 AMOUNT
And so on
How can I do this with oracle sql?

select ADD_MONTHS(trunc(sysdate), (rownum - 1) * 6) some_date
from dual
connect by level <= 5;
SOME_DATE
-----------
18.04.2014
18.10.2014
18.04.2015
18.10.2015
18.04.2016

WITH got_r_num AS
(
SELECT t.* -- OR WHATEVER YOU WANT
, DENSE_RANK () OVER ( PARTITION BY TRUNC (created_date, 'MONTH')
ORDER BY TRUNC (created_date) -- DESC
) AS r_num
FROM test_table
WHERE MOD ( MONTHS_BETWEEN ( TRUNC (SYSDATE)
, TRUNC (created_date)
)
, 6
) = 0
)
SELECT * -- or list all columns except r_num
FROM got_r_num
WHERE r_num = 1
;
Have a look here please .

If you need to sum of all records of 6 months in the AMOUNT field:
You can subquery with sum function and query with CONNECT BY LEVEL
SELECT x AS l_date,
(
SELECT sum(your_data)
FROM your_table
WHERE table_date >= x
AND table_date < add_months(x,6)
)AMOUNT
FROM(
SELECT add_months(to_date('01/06/2011','dd/mm/yyyy'),(LEVEL-1)*6) x
FROM dual
CONNECT BY LEVEL <= 4
);

Related

How to get the count of new unique ip address logged in to the website on each day using analytical function in sql?

Ex:
Date - up,
1/2 - 1.1.127.0 ,
1/3 - 1.1.127.1,
1/3 - 1.1.127.0,
1/4 - 1.1.127.3,
1/4 - 1.1.127.5,
1/5 - 1.1.127.3,
Output:
Date-count,
1/2 - 1,
1/3 - 1,
1/4 - 2,
1/5 -0
New and unique ip logged in in each day
You want to count how many IPs exist for a date that have not occurred on a previous date. You want to use analytic functions for this.
The number of new IDs is the total number of distinct IDs on a date minus the number of the previous date. In order to get this, first select the running count per row. Then aggregate per date to get the distinct number of IDs per date. Then use LAG to get the difference per day.
select
date,
max(cnt) - lag(max(cnt)) over (order by date) as new_ips
from
(
select date, count(distinct ip) over (order by date) as cnt
from mytable
) running_counts
group by date
order by date;
The same without analytic functions, which is probably more readable:
select date, count(distinct ip) as cnt
from mytable
where not exists
(
select null
from mytable before
where before.date < mytable.date
and before.id = mytable.id
)
group by date
order by date;
The DISTINCT in this latter query is not necessary, if there can be no duplicates (two rows with the same date and IP) in the table.
You can also use below solution using left join.
with t (dt, ip) as (
select to_date( '1/2', 'MM/DD' ), '1.1.127.0' from dual union all
select to_date( '1/3', 'MM/DD' ), '1.1.127.1' from dual union all
select to_date( '1/3', 'MM/DD' ), '1.1.127.0' from dual union all
select to_date( '1/4', 'MM/DD' ), '1.1.127.3' from dual union all
select to_date( '1/4', 'MM/DD' ), '1.1.127.5' from dual union all
select to_date( '1/5', 'MM/DD' ), '1.1.127.3' from dual
)
select t.DT, count( decode(t2.IP, null, 1, null) ) cnt
from t
left join t t2
on ( t2.DT < t.DT and t2.IP = t.IP )
group by t.DT
order by 1
;
demo

How can I get all dates in a query if there is not data in that dates?

Currently, I have a ORACLE query that gives me the following data:
As you can see, there is not data between the 11th and the 12th, and I would need to get this result if there is not data:
I currently have this query:
select
TRUNC(FECHA_PEDIDO, 'dd') AS FECHA,
PEDIDO,
COUNT(TRUNC(FECHA_PEDIDO, 'dd')) AS CANTIDAD
FROM PEDIDOS_TIENDA
GROUP BY TRUNC(FECHA_PEDIDO, 'dd'), PEDIDO
ORDER BY TRUNC(FECHA_PEDIDO, 'dd') ASC
I'm a little lost, can you help me?
You want something like:
SELECT c.fecha,
t.pedido,
COALESCE(t.cantidad, 0) AS cantidad
FROM (
SELECT min_fecha + LEVEL - 1 AS fecha
FROM (
SELECT MIN(TRUNC(FECHA_PEDIDO, 'dd')) AS min_fecha,
MAX(TRUNC(FECHA_PEDIDO, 'dd')) AS max_fecha
FROM PEDIDOS_TIENDA
)
CONNECT BY LEVEL - 1 <= max_fecha - min_fecha
) c
LEFT OUTER JOIN
(
SELECT TRUNC(FECHA_PEDIDO, 'dd') AS FECHA,
PEDIDO,
COUNT(TRUNC(FECHA_PEDIDO, 'dd')) AS CANTIDAD
FROM PEDIDOS_TIENDA
GROUP BY TRUNC(FECHA_PEDIDO, 'dd'), PEDIDO
ORDER BY TRUNC(FECHA_PEDIDO, 'dd') ASC
) t
ON c.fecha = t.fecha
ORDER BY fecha, pedido
Which, for the sample data:
CREATE TABLE PEDIDOS_TIENDA ( fecha_pedido, pedido ) AS
SELECT DATE '2020-12-09', 'Aleron' FROM DUAL UNION ALL
SELECT DATE '2020-12-09', 'Aleron' FROM DUAL UNION ALL
SELECT DATE '2020-12-10', 'Bugia' FROM DUAL UNION ALL
SELECT DATE '2020-12-10', 'Focos' FROM DUAL UNION ALL
SELECT DATE '2020-12-10', 'Ruedas' FROM DUAL UNION ALL
SELECT DATE '2020-12-10', 'Focos' FROM DUAL UNION ALL
SELECT DATE '2020-12-11', 'Llantas' FROM DUAL UNION ALL
SELECT DATE '2020-12-13', 'Llantas' FROM DUAL;
Outputs:
FECHA
PEDIDO
CANTIDAD
09-DEC-20
Aleron
2
10-DEC-20
Bugia
1
10-DEC-20
Focos
2
10-DEC-20
Ruedas
1
11-DEC-20
Llantas
1
12-DEC-20
0
13-DEC-20
Llantas
1
db<>fiddle here
You can use following query . using table t2, calculate the dates between the smallest date and the largest date, and then right outer join it to the main table.
SELECT t2.dt AS fecha,t1.pedido,COALESCE(t1.cantidad,0)
FROM mytable t1
RIGHT OUTER JOIN
(SELECT (SELECT MIN(fecha) FROM mytable) + level - 1 dt
FROM DUAL CONNECT BY level <= ((SELECT MAX(fecha) FROM mytable) - (SELECT MIN(fecha) FROM mytable) + 1)) t2
ON t1.fecha = t2.dt
ORDER BY t2.dt
demo in db<>fiddle

SQL display date on fixed frequency

I am trying to create a query which displays dates in a specific interval.For example if I have an hire_date and the min(hire_date) is 2009-01-01 and the max(hire_date) is 2009-03-1, then the table should display hire_date in frequency of 2 days apart. Like:
+---------+
hire_date
+---------+
2009-01-01
2009-01-03
2009-01-05
2009-01-07
..........
The table named Employee_Service contains:
ID Number
Hire_date Timestamp
Name Varchar
The current query that I use is:
select trunc(hire_date) "Date",
count(id) "Num Empl Opened"
from Employee_Service
group by trunc(hire_date)
order by trunc(hire_date)
Is there any way to build a query for this.
You can try:
select trunc(hire_date) "Date",
count(id) "Num Empl Opened"
from Employee_Service
where mod(to_char(hire_date,'dd'),2)<>0
and trunc(hire_date) between to_date('2009-01-01','yyyy-mm-dd') and to_date('2009-03-01','yyyy-mm-dd')
group by trunc(hire_date)
order by trunc(hire_date)
Try this:
WITH DAYS AS
(SELECT TRUNC(TO_DATE('2009-03-01','YYYY-mm-dd')) - ROWNUM*2 D
FROM ALL_OBJECTS
WHERE ROWNUM < 365)
SELECT
DAYS.D
FROM
DAYS WHERE D >= TO_DATE('2009-01-01','YYYY-mm-dd');
Demo
I guess this query like this would help you
select to_date('01/05/2014','DD/MM/YYYY') + level -1 HIRE_DATE
from dual
WHERE MOD(LEVEL,2) <> 0
connect by level <= to_date('01/06/2014','DD/MM/YYYY') - to_date('01/05/2014','DD/MM/YYYY') +1;
WHERE '01/05/2014' is taken as from date and '01/06/2014' is taken as to date.
So your query would be:
IF hire_date is a VARCHAR in DD/MM/YYYY format
select to_date(min(hire_date),'DD/MM/YYYY') + level -1 HIRE_DATE
from dual
WHERE MOD(LEVEL,2) <> 0
connect by level <= to_date(max(hire_date),'DD/MM/YYYY') - to_date(min(hire_date),'DD/MM/YYYY') +1;
Or,
IF HIRE_DATE IS A DATE FIELD,
select (min(hire_date)) + level -1 HIRE_DATE
from dual
WHERE MOD(LEVEL,2) <> 0
connect by level <= (max(hire_date)) - (min(hire_date)) +1;
EDIT:
Max and Min cannot be used with Group by. So use below format:
with cte as
(
select max(hire_date) max_date, min(hire_date) min_date from my_table
where --- all conditions here
and rownum=1
)
select (min_date + level -1) hire_dates
from dual
WHERE MOD(LEVEL,2) <> 0
connect by level <= ( max_date - min_date +1 );
with cte as
(
select max(hire_date) max_date, min(hire_date) min_date from Employee_Service
)
select (min_date + level -1) "Date", count(id) "Num Empl Opened"
from Employee_Service , cte
WHERE MOD(LEVEL,2) <> 0
group by (min_date + level -1)
connect by level <= ( max_date - min_date +1 )
ORDER BY (min_date + level -1);

Display Distinct Dates Not Exist In Table

I have a table called maximo_products and have a field called product_date.
I need to display all distinct dates which are not in in maximo_products table in MON-YYYY format
between Jan-2014 and Dec-2014.
How can do this?
SQLFiddle with table structure and records.
Sample output (dates which are not available in table)
MAR-2014
APR-2014
JUN-2014
JUL-2014
SEP-2014
To get the missing months, you need to generate all the months. The following uses a simple formulation for getting 12 months. It then uses not in to figure out which have no values:
with mons as (
select rownum r, add_months('01-JAN-2014', rownum - 1) as mon
from dual
connect by rownum <= 12
)
select *
from mons
where not exists (select 1
from maximo_products mp
where to_char(mp.product_date, 'YYYY-MM') =
to_char(mons.mon, 'YYYY-MM')
)
order by r;
EDIT:
You can move the definition of mons into a subquery:
select *
from (select rownum r, add_months('01-JAN-2014', rownum - 1) as mon
from dual
connect by rownum <= 12
) mons
where not exists (select 1
from maximo_products mp
where to_char(mp.product_date, 'YYYY-MM') =
to_char(mons.mon, 'YYYY-MM')
)
order by r;

Filter rows by those created within a close timeframe

I have a application where users create orders that are stored in a Oracle database. I'm trying to find a bug that only happens when a user creates orders within 30 seconds of the last order they created.
Here is the structure of the order table:
order_id | user_id | creation_date
I would like to write a query that can give me a list of orders where the creation_date is within 30 seconds of the last order for the same user. The results will hopefully help me find the bug.
I tried using the Oracle LAG() function but it doesn't seem to with the WHERE clause.
Any thoughts?
SELECT O.*
FROM YourTable O
WHERE EXISTS (
SELECT *
FROM YourTable O2
WHERE
O.creation_date > O2.creation_date
AND O.user_id = O2.user_id
AND O.creation_date - (30 / 86400) <= O2.creation_date
);
See this in action in a Sql Fiddle.
You can use the LAG function if you want, you would just have to wrap the query into a derived table and then put your WHERE condition in the outer query.
SELECT distinct
t1.order_id, t1.user_id, t1.creation_date
FROM
YourTable t1
join YourTable t2
on t2.user_id = t1.user_id
and t2.creation_date between t1.creation_date - 30/86400 and t1.creation_date
and t2.rowid <> t1.rowid
order by 3 desc
Example of using LAG():
SELECT id, (pss - css) time_diff_in_seconds
, creation_date, prev_date
FROM
(
SELECT id, creation_date, prev_date
, EXTRACT(SECOND From creation_date) css
, EXTRACT(SECOND From prev_date) pss
FROM
(
SELECT id, creation_date
, LAG(creation_date, 1, creation_date) OVER (ORDER BY creation_date) prev_date
FROM
( -- Table/data --
SELECT 1 id, timestamp '2013-03-20 13:56:58' creation_date FROM dual
UNION ALL
SELECT 2, timestamp '2013-03-20 13:57:27' FROM dual
UNION ALL
SELECT 3, timestamp '2013-03-20 13:59:16' FROM dual
)))
--WHERE (pss - css) <= 30
/
ID TIME_DIFF_IN_SECONDS
--------------------------
1 0 <<-- if uncomment where
2 31
3 11 <<-- if uncomment where