I have 2 tables, orders and orderNotes:
orders:
orderID | customerID | orderName
--------+------------+-----------
1 | 1 | Test
2 | 1 | 1234
3 | 1 | Test 2
4 | 2 | ABC Test
orderNotes:
noteID | orderID | postedDate | message
-------+---------+----------------------+----------
1 | 1 | 2014-08-01 08:00:06 | Testing
2 | 1 | 2014-08-04 13:15:45 | Hello
3 | 2 | 2014-07-31 11:11:50 | Hi, World
4 | 2 | 2014-08-01 12:16:32 | Test 123
...I think you get the idea
What I want to do is to detect if any order has not been updated in X hours.
I've come up with this:
SELECT orders.orderID, postedDate FROM orders
JOIN orderNotes ON orders.orderID = orderNotes.orderID
WHERE orders.customerID = 1
AND postedDate <= NOW() - INTERVAL 2 HOUR
but, this checks every row in orderNotes. How can I get it to check only the last row? I want to know if any orders (by customerID = 1) have not been updated in 2 hours.
Here's a demo of my current SQL: http://sqlfiddle.com/#!2/d5fc2e/1
Create a view with maximum dates
CREATE VIEW maxOrderNotes AS
SELECT
orderID,
MAX(`postedDate`) AS postedDate
FROM
orderNotes
GROUP BY
orderID;
Use the view in join
SELECT orders.orderID, postedDate FROM orders
JOIN maxOrderNotes ON orders.orderID = maxOrderNotes.orderID
WHERE orders.customerID = 1
AND postedDate <= NOW() - INTERVAL 2 HOUR;
+---------+---------------------+
| orderID | postedDate |
+---------+---------------------+
| 1 | 2014-08-04 10:15:45 |
| 2 | 2014-08-01 12:16:32 |
+---------+---------------------+
sqlfiddle
I found a solution that seems to work.
SELECT orders.orderID, MAX(postedDate) AS maxDate
FROM orders
JOIN orderNotes ON orders.orderID = orderNotes.orderID
WHERE orders.customerID = 1
GROUP BY orders.orderID
HAVING MAX(postedDate) <= NOW() - INTERVAL 2 HOUR
DEMO: http://sqlfiddle.com/#!2/d5fc2e/16
Related
i have 2 tables(say customer and details) containing following data. I need to print the details of the people who have invested maximum amount.
Customer:
+------+------------+--------+
| name | visited | amount |
+------+------------+--------+
| xyz | 2018-04-11 | 100 |
| xyz | 2018-04-11 | 1000 |
| abc | 2018-02-21 | 500 |
| xyz | 2018-03-11 | 700 |
| abc | 2018-01-24 | 50 |
+------+------------+--------+
Details:
+------+------------+
| name | detail |
+------+------------+
| abc | california |
| xyz | hongkong |
+------+------------+
I have found the customer who have invested the maximum amount using the query
select name,sum(amount)
from (
select name,amount
from customer
where visited >= DATE_SUB(CURDATE(),INTERVAL 8 MONTH)
) as subtable
group by name
order by amount
limit 1;
i have the following output
+------+-------------+
| name | sum(amount) |
+------+-------------+
| xyz | 1800 |
+------+-------------+
now how do i find the details of xyz from details table? I need to do this all in a single query. My output must be like.
+------+------------+
| name | detail |
+------+------------+
| xyz | hongkong |
+------+------------+
My stuck, how to proceed this?
select d.name, d.details, sum(c.amount)
from details d
join customer c on c.name = d.name
where c.visited >= DATE_SUB(CURDATE(),INTERVAL 8 MONTH)
group by d.name
order by sum(c.amount) desc
limit 1
You need to JOIN to details table. I've decided to use subquery to limit the amount of rows being looked up for the join operation.
select c.name, d.detail
from (
select
name,
sum(amount) as sum_amount
from customer
where visited >= DATE_SUB(CURDATE(),INTERVAL 8 MONTH)
group by name
order by sum_amount
limit 1
) c
left join details d on c.name = d.name
Note that I've removed your subquery as it was superfluous.
To get the following outputs you can write query with join like below :
Output:-
+------+------------+
| name | detail |
+------+------------+
| xyz | hongkong |
+------+------------+
Query:-
select d.name, d.details
from details d
join customer cust on cust.name = d.name and
cust.visited >= DATE_SUB(CURDATE(),INTERVAL 8 MONTH)
group by d.name
order by sum(cust.amount) desc
limit 1;
If you want to print sum Amount along with that then you have to just add one more column in your select statement :
Output:-
+------+------------+--------------+
| name | detail | sum(amount) |
+------+------------+--------------+
| xyz | hongkong | 1800 |
+------+------------+--------------+
Query:-
select d.name, d.details, sum(cust.amount)
from details d
join customer cust on cust.name = d.name and
cust.visited >= DATE_SUB(CURDATE(),INTERVAL 8 MONTH)
group by d.name
order by sum(cust.amount) desc
limit 1;
This question already has answers here:
SQL select only rows with max value on a column [duplicate]
(27 answers)
Closed 5 years ago.
I would like to select the "top most" entry for each row with a duplicated column value.
Performing the following query -
SELECT *
FROM shop
ORDER BY shop.start_date DESC, shop.created_date DESC;
I get the result set -
+--------+---------+------------+--------------+
| row_id | shop_id | start_date | created_date |
+--------+---------+------------+--------------+
| 1 | 1 | 2017-02-01 | 2017-01-01 |
| 2 | 1 | 2017-01-01 | 2017-02-01 |
| 3 | 2 | 2017-01-01 | 2017-07-01 |
| 4 | 2 | 2017-01-01 | 2017-01-01 |
+--------+---------+------------+--------------+
Can I modify the SELECT so that I only get back the "top rows" for each unique shop_id -- in this case, row_ids 1 and 3. There can be 1..n number of rows with the same shop_id.
Similarly, if my query above returned the following order, I'd want to only SELECT row_ids 1 and 4 since those would be the "top most" entries each shop_id.
+--------+---------+------------+--------------+
| row_id | shop_id | start_date | created_date |
+--------+---------+------------+--------------+
| 1 | 1 | 2017-02-01 | 2017-01-01 |
| 2 | 1 | 2017-01-01 | 2017-02-01 |
| 4 | 2 | 2017-01-01 | 2017-07-01 |
| 3 | 2 | 2017-01-01 | 2017-01-01 |
+--------+---------+------------+--------------+
You can do this by using a subquery:
select s.*
from shop s
where s.row_id = (
select row_id
from shop
where shop_id = s.shop_id
order by start_date desc, created_date desc
limit 1
)
Mind the assumption of row_id being uniq for each shop_id in this query example.
Demonstration
Or like this:
select t.*
from shop t
join (
select t2.shop_id, t2.start_date, max(t2.created_date) as created_date
from shop t2
join (
select max(start_date) as start_date, shop_id
from shop
group by shop_id
) t3 on t3.shop_id = t2.shop_id and t3.start_date = t2.start_date
group by t2.shop_id, t2.start_date
) t1 on t1.shop_id = t.shop_id and t.start_date = t1.start_date and t.created_date = t1.created_date
Mind that in case there can be records with the same start_date and created_date for the same shop_id you would need to use another group by s.shop_id, s.start_date, s.created_date in the outer query (adding min(row_id) with other columns listed in the group by in select)
Demonstration
Try joining to a subquery which finds the "top" rows for each shop_id:
SELECT t1.*
FROM shop t1
INNER JOIN
(
SELECT shop_id, MIN(row_id) AS min_id
FROM shop
GROUP BY shop_id
) t2
ON t1.shop_id = t2.shop_id AND
t1.row_id = t2.min_id
ORDER BY
t1.start_date DESC,
t1.created_date DESC;
Demo
Have Users table, where users can have multiple accounts.
Table can look like this:
u_id | u_parent_d | date_added
1 | 1 | 2017-01-01
2 | 2 | 2017-01-04
3 | 1 | 2017-01-05
4 | 4 | 2017-01-06
5 | 2 | 2017-01-07
How can I order these records by date added but grouped connected accounts together
u_id | u_parent_d | date_added
5 | 2 | 2017-01-07
2 | 2 | 2017-01-04
4 | 4 | 2017-01-06
3 | 1 | 2017-01-05
1 | 1 | 2017-01-01
You can build your query in two steps. First of all get the maximum date for each u_parent_d
select u_parent_d, max(date_added) as max_date
from Users
group by u_parent_d
Then you can join this with the initial table, and use max_date for sorting
select t1.*
from Users t1
join (
select u_parent_d, max(date_added) as max_date
from Users
group by u_parent_d
) t2
on t1.u_parent_d = t2.u_parent_d
order by t2.max_date desc, t1.date_added desc
Order both by date and parent id:
SELECT * FROM users
ORDER BY u_parent_id, date_added DESC
So i have table cont_selling
---------------------------------
cont_selling_id | date |
---------------------------------
1 | 2015-05-24 |
2 | 2015-06-06 |
---------------------------------
table 02 cont_sold
----------------------------------------------------
cont_sold_id | cont_selling_id | price |
---------------------------------------------------
1 | 1 | 10 |
2 | 1 | 10 |
3 | 1 | 30 |
4 | 2 | 20 |
5 | 2 | 10 |
--------------------------------------------------
and table 03 payment
----------------------------------------------
payment_id | cont_selling_id | paid |
-----------------------------------------------
1 | 1 | 10 |
2 | 2 | 10 |
3 | 1 | 20 |
4 | 1 | 10 |
5 | 2 | 10 |
-----------------------------------------------
now i need to SELECT table based on
now i want to merge all these three tables based on cont_selling table cont_selling_id column
and want to SUM cont_sold table price column and payment table paid column
this is what i want to do
expecting output
---------------------------------------------
cont_selling_id | price | paid |
---------------------------------------------
1 | 50 | 40 |
2 | 30 | 20 |
---------------------------------------------
so i tried like this in mysql query but it give wrong sum result
SELECT
SUM(Z.price) as total,
SUM(P.amount) as paid
FROM cont_selling S
LEFT JOIN cont_sold Z
ON S.cont_selling_id = Z.cont_selling_id
LEFT JOIN payment P
ON S.cont_selling_id = P.cont_selling_id
GROUP BY S.cont_selling_id
for this above query i m getting output like this
---------------------------------------------
cont_selling_id | price | paid |
---------------------------------------------
1 | 150 | 40 |
2 | 60 | 120 |
---------------------------------------------
Here how you can do it using the aggegare part into inner queries and then join
select
cs.cont_selling_id,
price,
paid
from cont_selling cs
left join(
select sum(price) as price , cont_selling_id from cont_sold
group by cont_selling_id
)x on x.cont_selling_id = cs.cont_selling_id,
left join(
select sum(paid) as paid , cont_selling_id from payment
group by cont_selling_id
)y
on y.cont_selling_id = cs.cont_selling_id;
You should make two different queries with SUM and then combine them to get the desired result:
SELECT T1.cont_selling_id,T1.price,T2.paid
FROM
(SELECT c.cont_selling_id,SUM(cs.price) as price
FROM cont_selling c LEFT JOIN
cont_sold cs ON c.cont_selling_id=cs.cont_selling_id
GROUP BY c.cont_selling_id) as T1 JOIN
(SELECT c.cont_selling_id,SUM(p.paid) as paid
FROM cont_selling c LEFT JOIN
payment p ON p.cont_selling_id=c.cont_selling_id
GROUP BY c.cont_selling_id) as T2 ON T1.cont_selling_id=T2.cont_selling_id
Result:
cont_selling_id price paid
----------------------------
1 50 40
2 30 20
Sample result in SQL Fiddle.
This untested query should work:
with a as(select cont_selling_id , sum(price) as totalprice from cont_sold group by cont_selling_id),
with a as(select cont_selling_id , sum(paid) as totalpaid from payment group by cont_selling_id),
select c.cont_selling_id , totalprice, totalpaid from cont_selling c left join a.count_selling_id = c.count_selling_id
left join b.count_selling_id = c.count_selling_id
You have to create temporary tables, because there is no dependency between your table for price and paid.
I want to join 2 tables:
source_table
----------------------------------
| source_id label |
|----------------------------------|
| 1 Contact Form |
| 2 E-Mail |
| 3 Inbound Call |
| 4 Referral |
----------------------------------
related_table
---------------------------------------
| id created_at source |
|---------------------------------------|
| 1 2013-12-26 2 |
| 2 2013-12-26 2 |
| 3 2013-12-26 4 |
| 4 2013-12-25 1 |
| 5 2013-12-18 2 |
| 6 2013-12-16 4 |
| 7 2013-11-30 2 |
---------------------------------------
So that it looks like this:
---------------------------------------
| created_at source amount |
|---------------------------------------|
| 2013-12-26 E-Mail 2 |
| 2013-12-26 Referral 1 |
| 2013-12-25 Contact Form 1 |
| 2013-12-18 E-Mail 1 |
| 2013-12-16 Referral 1 |
---------------------------------------
I want to count the occurrences of each source in related_table grouped by the source for each date in the range.
But I'm not sure how to write the query.
Here's what I have so far:
SELECT DISTINCT
source_table.source_id,
source_table.label AS source,
related_table.created_at,
COUNT(*) AS amount
FROM source_table
INNER JOIN related_table
ON related_table.source=source_table.source_id AND
related_table.created_at>='2013-12-01' AND
related_table.created_at<='2013-12-31'
GROUP BY `source`
ORDER BY `created_at` ASC
I'm not very good with SQL, so the above query might be far off from what I need to have. All I know is that it doesn't work as expected.
My implementation:
select created_at, s.label, amount
from
(
select count(r.Source) as amount, r.source, r.created_at
from related_table r
group by r.source, r.created_at) a inner join source_table s
on a.source = s.source_id
where created_at between '2013-12-01' and '2013-12-31'
order by amount desc, created_at desc
http://sqlfiddle.com/#!2/841bd/2
adjusted demo to your example...
SELECT
created_at
,label as source
,COUNT(*) AS amount
FROM source_table
INNER JOIN related_table
ON source_table.source_id = related_table.source
GROUP BY label, created_at
ORDER BY created_at DESC