Select last date and all dates in the future - mysql

I'd like to select only the nearest date in the past and all the dates in the future.
I reach a result with the following query, but the results are side by side instead row per row.
How should I modifiy my query?
SELECT t1.*, t2.*
FROM
(SELECT *
FROM table1
WHERE from_p <= NOW()
AND prod = 3000
ORDER BY from_p DESC
LIMIT 1) AS t1
JOIN
(SELECT *
FROM table1
WHERE from_p >= NOW()
AND prod = 3000
ORDER BY from_p DESC
) AS t2

You need a use a subquery to first find "latest past date" and then write the main query based on that:
SELECT * FROM table1
WHERE from_p >= (
SELECT from_p FROM table1
WHERE from_p <= NOW() AND prod=3000
ORDER BY from_p DESC LIMIT 1
)
AND prod=3000
ORDER BY from_p;

Try:
(SELECT *
FROM table1
WHERE from_p <= NOW()
AND prod = 3000
ORDER BY from_p DESC
LIMIT 1)
UNION
(SELECT *
FROM table1
WHERE from_p >= NOW()
AND prod = 3000
ORDER BY from_p DESC)

Related

(MySQL 5.7) How to combine my two queries?

How can I combine my two queries in MySQL 5.7:
(windows functions doesn't work)
1: This query is finding all dialogues where more than 10 messages and spaced at least an hour apart.
SELECT `dialog_id`
FROM `messages`
GROUP BY `dialog_id`
HAVING COUNT(*) >= 10
AND MIN(`timestamp`) + INTERVAL 1 HOUR < MAX(`timestamp`)
2: The second query selects two last rows for each dialogue.
SELECT * FROM messages tbl WHERE
(SELECT COUNT(*) FROM messages tbl1 WHERE tbl1.dialog_id = tbl.dialog_id AND tbl1.id >= tbl.id AND
(user_from = :user_from OR user_to = :user_to)) <= 2 ORDER BY dialog_id DESC
So, what I want is to select last two rows for each dialogue that lasted more than an hour and where more than 10 messages were sent.
Though I didn't got you properly is this what you are looking for:
SELECT * FROM messages tbl WHERE
(SELECT COUNT(*) FROM messages tbl1 WHERE tbl1.dialog_id = tbl.dialog_id AND tbl1.id >= tbl.id AND
(user_from = :user_from OR user_to = :user_to)) <= 2
and dialog_id in (SELECT `dialog_id`
FROM `messages`
GROUP BY `dialog_id`
HAVING COUNT(*) >= 10
AND MIN(`timestamp`) + INTERVAL 1 HOUR < MAX(`timestamp`))
ORDER BY dialog_id DESC
One way you can accomplish this with a subquery:
SELECT *
FROM messages tbl
WHERE (
SELECT COUNT(*)
messages tbl1
tbl1.dialog_id = tbl.dialog_id
tbl1.id >= tbl.id
(user_from = :user_from OR user_to = :user_to)) <= 2
and dialog_id in (
SELECT `dialog_id`
FROM `messages`
GROUP BY `dialog_id`
HAVING COUNT(*) >= 10
AND MIN(`timestamp`) + INTERVAL 1 HOUR < MAX(`timestamp`))
ORDER BY dialog_id DESC
You might have to adjust it slightly, since I don't have the full structure of your tables, but the principle would go as follows: get all the dialogue_ids matching your 10 and over an hour criteria, then use it to limit the messages returned from your "Get the most recent two" logic.

SQL query for each ID in table

I have a query for 1 particular customer_id. How can I execute this query for each customer_id in table?
SELECT *
FROM table
WHERE date <= '2015-12-31 23:59:59' AND customer_id = 100
ORDER BY date DESC
LIMIT 1
You can use NOT EXISTS():
SELECT * FROM YourTable t
WHERE t.date <= '2015-12-31 23:59:59'
AND NOT EXISTS(SELECT 1 FROM YourTable s
WHERE t.customer_id = s.customer_id
AND t.date < s.date)
This will select only a record after the date filter where NOT EXISTS another record for the same id with a bigger date. Its basically the same as limit 1 for all.
You can use Inner join:
SELECT * FROM YourTable t INNER JOIN
(SELECT * FROM Table) s
ON t.customer_id = s.customer_id
WHERE t.date = '2015-12-31 23:59:59'
ORDER BY date DESC

SQL Query to group and add time between consecutive rows

Need help with SQL Query (MySQL)
Say I have a table with data as..
The table has the Latitude and Longitude locations logged for a person at some time intervals (TIME column), And DISTANCE_TRAVELLED column has the distance traveled from its previous record.
If i want to know how many minutes a person was not moving (i.e DISTANCE_TRAVEKLLED <= 0.001)
what query should i use?
Can we also group the data by Date? Basically i want to know how many minutes the person was idle in a specific day.
You need to get the previous time for each record. I like to do this using a correlated subquery:
select t.*,
(select t2.time
from table t2
where t2.device = t.device and t2.time < t.time
order by time desc
limit 1
) as prevtime
from table t;
Now you can get the number of minutes not moved, as something like:
select t.*, TIMESTAMPDIFF(MINUTE, prevftime, time) as minutes
from (select t.*,
(select t2.time
from table t2
where t2.device = t.device and t2.time < t.time
order by time desc
limit 1
) as prevtime
from table t
) t
The rest of what you request is just adding the appropriate where clause or group by clause. For instance:
select device, date(time), sum(TIMESTAMPDIFF(MINUTE, prevftime, time)) as minutes
from (select t.*,
(select t2.time
from table t2
where t2.device = t.device and t2.time < t.time
order by time desc
limit 1
) as prevtime
from table t
) t
where distance_travelled <= 0.001
group by device, date(time)
EDIT:
For performance, create an index on table(device, time).

select 10 rows forwards and 10 backwards from a date

I'm trying to select 10 rows from today's date in either direction (forward and backwards in time) and in date order. The best I've got so far is:
SELECT * FROM (
SELECT * FROM foo WHERE dt >= now() ORDER BY dt ASC LIMIT 10
UNION
SELECT * FROM foo WHERE dt < now() ORDER BY dt DESC LIMIT 10
) ORDER BY dt ASC;
Is there a nicer/more efficient way to do this?
Thanks.
Your idea is sound, but this is the correct query for it.
SELECT * FROM (
SELECT * FROM (SELECT * FROM foo WHERE dt >= now() ORDER BY dt ASC LIMIT 10) A
UNION ALL
SELECT * FROM (SELECT * FROM foo WHERE dt < now() ORDER BY dt DESC LIMIT 10) B
) C
ORDER BY dt ASC;
Only one ORDER BY clause is permitted per level of query, so you actually need to further subquery the A and B parts shown. Also, UNION ALL avoids a sort operation, since you know the two sets are distinct.
An index on foo.dt will ensure that this query is as fast as can be.
Instead of you can use simple query
(SELECT * FROM one WHERE dt >= now() ORDER BY dt ASC LIMIT 10)
UNION ALL
(SELECT * FROM one WHERE dt < now() ORDER BY dt DESC LIMIT 10)

Mysql self join with multiple order by

assume we have table
id, title, date
I need to build 1 query to:
select date = TODAY, order by id
select data < TODAY, order by date desc,
select data > TODAY, order by date asc,
I think you need to use UNION and sub queries:
SELECT * FROM (
SELECT *
FROM YourTable
WHERE Date(dateField) = Date(Now())
ORDER BY ID
) t1
UNION
SELECT * FROM (
SELECT *
FROM YourTable
WHERE dateField < Now()
ORDER BY dateField DESC
) t2
UNION
SELECT * FROM (
SELECT *
FROM YourTable
WHERE Date(dateField) > Now()
ORDER BY dateField
) t3
Here is a simplified SQL Fiddle example.
Good luck.