Mysql self join with multiple order by - mysql

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.

Related

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

Reverse order for GROUP BY in MySQL

I need to select first value for every hour from my db. But I don't know how to reverse order on GROUP BY statement.
How can i rewrite my query (now it selects last value in hour)?
SELECT HOUR(`time`) as hour, mytable.*
FROM mytable
WHERE DATE(`time`) ="2015-09-12" GROUP BY HOUR(`time`) ORDER BY `time` ASC;
This query gave me expected result:
SELECT HOUR(`time`) as hour, sortedTable.* FROM
(SELECT electrolysis.* FROM electrolysis
WHERE DATE(`time`)='2015-09-12' ORDER BY `time`) as sortedTable
GROUP BY HOUR(`time`);
You can just select the MIN HOUR in sub query , try using the query:
SELECT * from mytable WHERE `time` IN (
SELECT MIN(HOUR(`time`)) as `hour`
FROM mytable
WHERE DATE(`time`) ="2015-09-12"
GROUP BY HOUR(`time`) ) ORDER BY `time` ASC;
You can do something like this:-
SELECT sub0.min_time,
mytable.*
FROM mytable
INNER JOIN
(
SELECT MIN(`time`) AS min_time
FROM mytable
GROUP BY HOUR(`time`)
) sub0
ON mytable.`time` = sub0.min_time
WHERE DATE(`time`) ="2015-09-12"
ORDER BY `time` ASC
This is using a sub query to get the smallest time in each hour. This is then joined back against your main table on this min time to get the record that has this time.
Note that there is a potential problem here if there are multiple records that share the same time as the smallest one for an hour. There are ways around this, but that will depend on your data (eg, if you have a unique id field which is always ascending with time then you could select the min id for each hour and join based on that)
You can use below query, which is more optimized just make sure that time field should be indexed.
SELECT HOUR(m.time), m.*
FROM mytable AS m
JOIN
(
SELECT MIN(`time`) AS tm
FROM mytable
WHERE `time` >= '2015-09-12 00:00:00' AND `time` <= '2015-09-12 23:59:59'
GROUP BY HOUR(`time`)
) AS a ON m.time=a.tm
GROUP BY HOUR(m.time)
ORDER BY m.time;

Select last date and all dates in the future

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)

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)

How to display records from two tables slectively in the order of when they are created

Lets say we have two tables with id and timestamp columns.
How can we display the ids of first 10 records from both the tables selectively in the order of timestamp.
e.g 1st we created a record in table1, then we created a record in table2, then we created a record in table1, then we created a record in table2 ........ so on.
Depending on your RDBMS, you can use ROWNUM, LIMIT, or create your own Row_Number with Row_Number() OVER (ORDER BY datefield DESC).
This might work (for Oracle).
select *
from
( select id, datefield from Table1
union select id, datefield From Table2 order by datefield desc ) t
where ROWNUM <= 10;
And for MySQL:
select *
from
( select id, datefield from table
union select id, datefield from table2 ) t
order by datefield desc
limit 10;
And for SQL Server:
select *
from
(
select *, Row_Number() OVER (ORDER BY datefield DESC) as rown
from
( select id, datefield from table
union select id, datefield from table2 ) t
) t2
where rown <= 10
Good luck.
I am not sure if is this what you are looking for. This will work in MySql:
SELECT 'table1' tab, id, timestamp
FROM table1
UNION ALL
SELECT 'table2' tab, id, timestamp
FROM table2
ORDER BY timestamp DESC
LIMIT 10
and will select last 10 records inserted in one of table1 or table2. This will work in SQL Server:
SELECT TOP 10 * FROM (
SELECT TOP 10 'table1' tab, id, timestamp
FROM table1
ORDER BY timestamp DESC
UNION ALL
SELECT TOP 10 'table2' tab, id, timestamp
FROM table2
ORDER BY timestamp DESC ) t
ORDER BY timestamp DESC