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
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
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;
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!!
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
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