SQL: Find the longest date gap from multiple table - sql

i need some help.
I have two tables like this.
Table Person
p_id | name | registration date
-----------------------------
1 | ABC | 2018-01-01
2 | DEF | 2018-02-02
3 | GHI | 2018-03-01
4 | JKL | 2018-01-02
5 | MNO | 2018-02-01
6 | PQR | 2018-03-02
Table Order
Order_id| p_id | order_date
----------------------------
123 | 1 | 2018-01-05
345 | 2 | 2018-02-06
678 | 3 | 2018-03-07
910 | 4 | 2018-01-08
012 | 3 | 2018-03-04
234 | 4 | 2018-01-05
567 | 5 | 2018-02-08
890 | 6 | 2018-03-09
I need to find out how many days is the longest period when this two table aren't updated.
What's the easiest query to get the result in SQL?
Thank you
UPDATE:
The result should be showing the longest date gap between order_date and registration_date. Because the longest date gap is 2018-01-08 and 2018-02-01, so the result should return '24'

Try this:
SELECT MAX(DATE_PART('day', now() - '2018-02-15'::TIMESTAMP)) FROM person p
JOIN order o
USING (p_id)

Assuming current PostgreSQL and lots of orders per person on avg., this should be among the fastest options:
SELECT o.order_date - p.registration_date AS days
FROM person p
CROSS JOIN LATERAL (
SELECT order_date
FROM "order" -- order is a reserved word!
WHRE p_id = p.p_id
ORDER BY 1 DESC -- assuming NOT NULL
LIMIT 1
) o
ORDER BY 1 DESC
LIMIT 1;
Needs an index on "orders"(p_id, order_date).
Detailed explanation:
Optimize GROUP BY query to retrieve latest record per user
Select first row in each GROUP BY group?

You seem to want:
select max(o.order_date - p.registration_date)
from person p join
orders o
on p.p_id = o.p_id;

select max((date_part('day',age(order_date, "registration date")))) + 1 as dif
from (
select "p_id" ,max(order_date) order_date
from "Order"
group by "p_id"
) T1
left join Person T2 on T1.p_id = T2.p_id
| maxday |
|--------|
| 8 |
[SQL Fiddle DEMO LINK]

Related

SQL: usage time of item between dates combining two tables

Trying to create query that will give me usage time of each car part between dates when that part is used. Etc. let say part id 1 is installed on 2018-03-01 and on 2018-04-01 runs for 50min and then on 2018-05-10 runs 30min total usage of this part shoud be 1:20min as result.
These are examples of my tables.
Table1
| id | part_id | car_id | part_date |
|----|-------- |--------|------------|
| 1 | 1 | 3 | 2018-03-01 |
| 2 | 1 | 1 | 2018-03-28 |
| 3 | 1 | 3 | 2018-05-10 |
Table2
| id | car_id | run_date | puton_time | putoff_time |
|----|--------|------------|---------------------|---------------------|
| 1 | 3 | 2018-04-01 | 2018-04-01 12:00:00 | 2018-04-01 12:50:00 |
| 2 | 2 | 2018-04-10 | 2018-04-10 15:10:00 | 2018-04-10 15:20:00 |
| 3 | 3 | 2018-05-10 | 2018-05-10 10:00:00 | 2018-05-10 10:30:00 |
| 4 | 1 | 2018-05-11 | 2018-05-11 12:00:00 | 2018-04-01 12:50:00 |
Table1 contains dates when each part is installed, table2 contains usage time of each part and they are joined on car_id, I have try to write query but it does not work well if somebody can figure out my mistake in this query that would be healpful.
My SQL query
SELECT SEC_TO_TIME(SUM(TIME_TO_SEC(TIMEDIFF(t1.puton_time, t1.putoff_time)))) AS total_time
FROM table2 t1
LEFT JOIN table1 t2 ON t1.car_id=t2.car_id
WHERE t2.id=1 AND t1.run_date BETWEEN t2.datum AND
(SELECT COALESCE(MIN(datum), '2100-01-01') AS NextDate FROM table1 WHERE
id=1 AND t2.part_date > part_date);
Expected result
| part_id | total_time |
|---------|------------|
| 1 | 1:20:00 |
Hope that this problem make sence because in my search I found nothing like this, so I need help.
Solution, thanks to Kota Mori
SELECT t1.id, SEC_TO_TIME(SUM(TIME_TO_SEC(TIMEDIFF(t2.puton_time, t2.putoff_time)))) AS total_time
FROM table1 t1
LEFT JOIN table2 t2 ON t1.car_id = t2.car_id
AND t1.part_date >= t2.run_date
GROUP BY t1.id
You first need to join the two tables by the car_id and also a condition that part_date should be no greater than run_date.
Then compute the total minutes for each part_id separately.
The following is a query example for SQLite (The only SQL engine that I have access to right now).
Since SQLite does not have datetime type, I convert strings into unix timestamp by strftime function. This part should be changed in accordance with the SQL engine you are using. Apart from that, this is fairly a standard sql and mostly valid for other SQL dialect.
SELECT
t1.id,
sum(
cast(strftime('%s', t2.putoff_time) as integer) -
cast(strftime('%s', t2.puton_time) as integer)
) / 60 AS total_minutes
FROM
table1 t1
LEFT JOIN
table2 t2
ON
t1.car_id = t2.car_id
AND t1.part_date <= t2.run_date
GROUP BY
t1.id
The result is something like the below. Note that ID 1 gets 80 minutes (1:20) as expected.
id total_minutes
0 1 80
1 2 80
2 3 30

How can I SELECT MAX(VALUE) from duplicate values which occur multiple time within each month?

I have records for each user which occur multiple times each month. I wish to select just the highest value from the repeated values for each month for each user.
Table schema
custacc
ID | ac_no | DODSTART | od_limit
---+--------+------------+----------
1 | 110011 | 2019-02-10 | 200,000
2 | 110011 | 2019-02-12 | 120,000
3 | 110014 | 2019-02-10 | 70,000
4 | 110014 | 2019-02-12 | 10,000
5 | 110009 | 2019-02-10 | 30,000
customer
ID | cust_no | name | cust_type
---+---------+-------+----------
1 | 110011 | Jame | M
2 | 110014 | Fred | N
3 | 110009 | Ahmed | M
How can I achieve this>
What I tried so far:
SELECT
custacc.ac_no,
custacc.od_limit,
custacc.DODSTART,
customer.name,
custacc.gl_no,
custacc.USERNAME,
customer.cust_type
FROM
custacc
LEFT JOIN
customer ON custacc.ac_no = customer.cust_no
INNER JOIN
(SELECT
MAX(DODSTART) LAST_UPDATE_DATE_TIME,
ac_no
FROM
custacc
GROUP BY
ac_no) s2 ON custacc.ac_no = s2.ac_no
AND custacc.DODSTART = s2.LAST_UPDATE_DATE_TIME
WHERE
custacc.od_limit != 0.00
The query doesn't return the expected result.
Try this(add columns that you need):
This is Oracle solution since you didn't mention it in your question:
SELECT ID,MAX(OD_LIMIT) OVER(PARTITION BY ID,EXTRACT(MONTH FROM DODSTART)) FROM CUSTACC;

Join two tables based on date from first

I have two tables like below (date format: yyyy-MM-dd):
1) Table1 - SURGERY
P_ID | SURGERY_DATE
------------------------------------------------
1 | 2012-04-01
2 | 2012-08-14
1 | 2012-07-22
4 | 2012-10-30
3 | 2012-06-07
2) Table2 - VISIT
P_ID | VISIT_DATE
-----------------------------------------
1 | 2012-03-28
1 | 2012-04-14
1 | 2012-05-17
1 | 2012-09-12
3 | 2012-07-15
4 | 2012-10-10
3 | 2012-06-01
The tables SURGERY and VISIT are joined from other tables. I would like to find all records that meet the following criteria: VISIT_DATE >= SURGERY_DATE
3) Result table
EMPLOYEE_ID | SUGERY_DATE | NUMBER OF VISIT
-------------------------------------------------------
1 | 2012-04-01 | 4
2 | 2012-08-14 | 0
1 | 2012-07-22 | 2
4 | 2012-10-30 | 1
3 | 2012-06-07 | 1
Using group by and count can solve your problem.
Please try the code below.
(https://i.stack.imgur.com/NFzdf.jpg)
You can use a correlated subquery:
select s.*,
(select count(*)
from visit v
where v.p_id = s.p_id and v.visit_date > s.surgery_date
) as num_visits_after
from surgery s;
You need to use group by and count with a mentioned condition like the following:
SELECT
S.P_ID,
S.SURGERY_DATE,
SUM(CASE
WHEN V.VISIT_DATE > S.SURGERY_DATE THEN 1
END) AS NUM_VISITS_AFTER
FROM
SURGERY S
LEFT JOIN VISIT V ON ( S.P_ID = V.P_ID )
GROUP BY
S.P_ID,
S.SURGERY_DATE;
Cheers!!

Get a partitioned sum of a column in a fixed time window for each record

TelNo | OrderDate | Orders
A | 2017-01-01 | 5
A | 2017-02-02 | 4
A | 2017-07-05 | 6
A | 2017-09-10 | 10
B | 2017-03-01 | 3
B | 2017-04-12 | 6
B | 2017-11-10 | 4
Above is the order table, requirement is to find the sum of 'Orders' for each 'TelNo' within last 6 months from the 'OrderDate' against each record of the table. Below is the expected output;
TelNo | OrderDate | Sum_of_orders
A | 2017-01-01 | 5
A | 2017-02-02 | 9
A | 2017-07-05 | 10
A | 2017-09-10 | 16
B | 2017-03-01 | 3
B | 2017-04-12 | 9
B | 2017-11-10 | 4
I've tried different combinations of CTE and sum(case -- ) over (partition by --) approaches(sql-server-2016), but didn't arrive at a solution. Appreciate if someone can help out in this.
You can use a query like below to get your desired results
See working demo
select t1.TelNo, t1.OrderDate, Sum_of_orders =sum(t2.Orders)
from t t1
join t t2
on t1.TelNo=t2.Telno
and t2.OrderDate between DATEADD(m,-6,t1.OrderDate) and t1.OrderDate
group by t1.TelNo, t1.OrderDate
I would use apply :
select t.TelNo, t.OrderDate, tt.Sum_of_orders
from table t cross apply (
select sum(t1.orders) Sum_of_orders
from table t1
where t1.TelNo = t.TelNo and
t1.OrderDate >= dateadd(mm, -6, t.orderdate) and
t1.OrderDate <= t.OrderDate
) tt;
You can use below query to get desired results:
select mt.TelNo, mt.OrderDate, sum(mt1.orders) from MyTbl mt
left join MyTbl mt1 on mt.TelNo = mt1.TelNo and datediff(day,mt1.OrderDate, mt.OrderDate) <= 180
and mt1.orderdate <= mt.OrderDate
Group by mt.TelNo, mt.OrderDate
order by 1,2

How can I do SQL query count based on certain criteria including row order

I've come across certain logic that I need for my SQL query. Given that I have a table as such:
+----------+-------+------------+
| product | valid | Date |
+----------+-------+------------+
| 1 | null | 2016-05-10 |
| 1 | null | 2016-05-09 |
| 1 | yes | 2016-05-08 |
+----------+-------+------------+
This table is produced by a simple query:
SELECT * FROM products WHERE product = 1 ORDER BY date desc
Now what I need to do is create a query to count the number of nulls for certain products by order of date until there is a yes value. So the above example the count would be 2 as there are 2 nulls until a yes.
+----------+-------+------------+
| product | valid | Date |
+----------+-------+------------+
| 2 | null | 2016-05-10 |
| 2 | yes | 2016-05-09 |
| 2 | null | 2016-05-08 |
+----------+-------+------------+
Above would return 1 as there is 1 null until a yes.
+----------+-------+------------+
| product | valid | Date |
+----------+-------+------------+
| 3 | yes | 2016-05-10 |
| 3 | yes | 2016-05-09 |
| 3 | null | 2016-05-08 |
+----------+-------+------------+
Above would return 0.
You need a Correlated Subquery like this:
SELECT COUNT(*)
FROM products AS p1
WHERE product = 1
AND Date >
( -- maximum date with 'yes'
SELECT MAX(Date)
FROM products AS p2
WHERE p1.product = p2.product
AND Valid = 'yes'
)
This should do it:
select count(1) from table where valid is null and date > (select min(date) from table where valid = 'yes')
Not sure if your logic provided covers all the possible weird and wonderful extreme scenarios but the following piece of code would do what you are after:
select a.product,
count(IIF(a.valid is null and a.date >maxdate,a.date,null)) as total
from sometable a
inner join (
select product, max(date) as Maxdate
from sometable where valid='yes' group by product
) b
on a.product=b.product group by a.product