I want to query 2 tables with (almost) identical rows at the same time. As a result, I want to get the 5 recent entries (ordered by date, in total), no matter from which table they are from
So far, I tried this:
SELECT date, name, text FROM `table_A`
UNION
SELECT date, name, text FROM `table_B` ORDER BY date desc LIMIT 5
Unfortunately, this query takes about 20 seconds (both tables have ~300.000 rows).
When I just do:
SELECT date, name, text FROM `table_A` ORDER BY date desc LIMIT 5
or
SELECT date, name, text FROM `table_B` ORDER BY date desc LIMIT 5
the query takes only a few milliseconds.
So my question is: How can I improve my query to be faster or what select query should I use to get the 5 latest rows from both tables?
Select the most recent 5 rows in each table before combining them.
SELECT *
FROM (
(SELECT date, name, text FROM table_A ORDER BY date DESC LIMIT 5)
UNION
(SELECT date, name, text FROM table_B ORDER BY date DESC LIMIT 5)
) x
ORDER BY date DESC
LIMIT 5
The problem with your query is that it's first merging the entire tables and removing duplicates before doing the ordering and limiting. The merged table doesn't have an index, so that part is slow.
Related
I am not an SQL query wizard at all, and here is my problem:
I have those 3 separate querys that works very well and each one gives me a nice looking frame with results on my website.
SELECT arretsautressb AS Raison, SUM(minutesarrets) AS Minutes
FROM rapport_production_salles_blanches_2_repeat
GROUP BY Raison
ORDER BY Minutes DESC
SELECT redresseuseminutesarrets AS Raison, SUM(minutesarretsredresseuse) AS Minutes
FROM rapport_production_salles_blanches_3_repeat
GROUP BY Raison
ORDER BY Minutes DESC
SELECT raisonarretsconvoyeurair AS Raison, SUM(minutesarretsconvoyeurair) AS Minutes
FROM rapport_production_salles_blanches_4_repeat
GROUP BY Raison
ORDER BY Minutes DESC
So everything is fine with those 3 results...the Raison column in my table return all the rows and the Minutes query SUM all rows Group by Raison...
but i would like to merge those querys so it would give me only 1 big table with the results,instead on 3 tables.
But no matter how i try to format my UNION ALL code, what i get is 1 result only from each Raison query (so it takes only 1 row in sql table), instead of all the rows when they are separated. but the Minutes query is doing fine calculating the SUM of all the rows.
It would be cool if someone would just show me how to do it...cause i have been reading documentation for a couple of hours, and i am still stuck on this one.
This is what i tried so far, no error, but only 1 row of Raison is taken from sql table, instead of all rows:
SELECT *
FROM ( (SELECT arretsautressb AS Raison,
SUM(minutesarrets) AS Minutes
FROM rapport_production_salles_blanches_2_repeat t1)
UNION ALL
(SELECT redresseuseminutesarrets AS Raison,
SUM(minutesarretsredresseuse) AS Minutes
FROM rapport_production_salles_blanches_3_repeat t2)
UNION ALL
(SELECT raisonarretsconvoyeurair AS Raison,
SUM(minutesarretsconvoyeurair) AS Minutes
FROM rapport_production_salles_blanches_4_repeat t3)
) AS t123
GROUP BY Raison
ORDER BY Minutes DESC
This is what i get from my UNION ALL query:
UNION ALL
But this is what i get from 3 separated querys:
3 querys
I think your query doesn't return your desired result because of the following things:
It's fine to use a sub query where you specify the three tables and union them. However, you cannot use an aggregate (in this case SUM) without the use of GROUP BY.
Next, whenever you use GROUP BY, you should refer to the attribute instead of the column name. In my query I changed GROUP BY Raison to GROUP BY t1.arretsautressb.
I have used an ORDER BY on the outer query and I order by the second column, which is in this case the SUM(minutesarrets).
The query I would use is the following:
SELECT *
FROM (
SELECT arretsautressb AS Raison
, SUM(minutesarrets) AS sum_minutes
FROM rapport_production_salles_blanches_2_repeat AS t1
GROUP BY t1.arretsautressb
UNION ALL
SELECT redresseuseminutesarrets AS Raison
, SUM(minutesarretsredresseuse) AS sum_minutes
FROM rapport_production_salles_blanches_3_repeat AS t2
GROUP BY t2.redresseuseminutesarrets
UNION ALL
SELECT raisonarretsconvoyeurair AS Raison
, SUM(minutesarretsconvoyeurair) AS sum_minutes
FROM rapport_production_salles_blanches_4_repeat AS t3
GROUP BY t3.raisonarretsconvoyeurair
) AS t123
ORDER BY 2 DESC
Try this:
SELECT * FROM (
SELECT * FROM (
(SELECT arretsautressb AS Raison, SUM(minutesarrets) AS Minutes FROM rapport_production_salles_blanches_2_repeat t1)
UNION ALL
(SELECT redresseuseminutesarrets AS Raison, SUM(minutesarretsredresseuse) AS Minutes FROM rapport_production_salles_blanches_3_repeat t2)
) t1
UNION All
(SELECT raisonarretsconvoyeurair AS Raison, SUM(minutesarretsconvoyeurair) AS Minutes FROM rapport_production_salles_blanches_4_repeat t3)
) AS t123 GROUP BY t123.Raison ORDER BY t123.Minutes DESC
This is what I last tried.
(
SELECT
`offers`.`id` AS `offer`, `offers`.`date`
from `offers`
WHERE `offers`.`expired`='0'
ORDER BY `offers`.`date` DESC LIMIT 10
)
UNION ALL
(
SELECT
`vlog`.`video`,
`vlog`.`updated`
from `vlog`
ORDER BY `vlog`.`date` DESC LIMIT 10
)
For simplicity's sake, I have only two columns. I need to sort them by the date (not in the same results the code above provides) and show which is an offer and which is a video. Is this possible with no columns that link the tables.?
I'm assuming that video.video is an ID, since it lines up with the id column in the top query. You can select a literal string in both queries to indicate which query it came from:
SQL Fiddle
SELECT
'offer' AS type,
id,
date
FROM
offers
WHERE
expired = 0
UNION
SELECT
'video' AS type,
video AS id,
updated AS date
FROM
vlog
ORDER BY
date
I need to show ordered 20 records on my grid but I can't use LIMIT because of my generator(Scriptcase) using LIMIT to show lines per page. It's generator's bug but I need to solve it for my project. So is it possible to show 20 ordered record from my table with a query?
As from comments,if you can't use limit then you can rank your results on basis of some order and in parent select filter limit the results by rank number
select * from (
select *
,#r:=#r + 1 as row_num
from your_table_name
cross join (select #r:=0)t
order by some_column asc /* or desc*/
) t1
where row_num <= 20
Demo with rank no.
Another hackish way would be using group_concat() with order by to get the list of ids ordered on asc/desc and substring_index to pick the desired ids like you need 20 records then join with same table using find_in_set ,But this solution will be very expensive in terms of performance and group_concat limitations if you need more than 20 records
select t.*
from your_table_name t
join (
select
substring_index(group_concat(id order by some_column asc),',',20) ids_list
from your_table_name
) t1 on (find_in_set(t.id , t1.ids_list) > 0)
Demo without rank
What about SELECT in SELECT:
SELECT *
FROM (
-- there put your query
-- with LIMIT 20
) q
So outer SELECT is without LIMIT and your generator can add own.
In a Scriptcase Grid, you CAN use Limit. This is a valid SQL query that selects only the first 20 records from a table. The grid is set to show only 10 records per page, so it will show 20 results split in a total of 2 pages:
SELECT
ProductID,
ProductName
FROM
Products
LIMIT 20
Also the embraced query works out well:
SELECT
ProductID,
ProductName
FROM
(SELECT
ProductID,
ProductName
FROM Products LIMIT 20) tmp
I have a table that has transactions with a datetime column. I'm trying to select the last 'n' records (i.e. 20 rows) but have it sorted oldest to newest.
SELECT *
FROM table
WHERE 1=1
ORDER BY table.datefield DESC
LIMIT 20;
Gives me the 20 most recent, but in the opposite order.
Is this possible in one query, or will I have to do a query to get total rows and then adjust the limit based on that so I can do the table.datefiled ASC and then limit (total rows - n), n
Building a SELECT around your original SELECT and convert this to a derived table should do it
SELECT t.*
FROM (
SELECT *
FROM table
WHERE 1=1
ORDER BY table.datefield DESC
LIMIT 20
) t
ORDER BY t.datefield
I have a mySQl db (name "stocks") with 50 tables, each tables with
id, symbol, date, time, open, high, low, close, volume as columns (9 columns).
I would like to know what is the last record for each table, ordered for date then time.
Should I have to ORDER BY all data for each table or there is a better way to just know last record?
I am asking help for a query that just return only last record for each table in db.
Thanks
PS For last record I mean most recent as Date then Time
There are two options how to do that:
-- I would use this only if you need more than one records
SELECT * FROM table ORDER BY date DESC LIMIT 1;
-- Way to go:
SELECT * FROM table WHERE date = (SELECT MAX(date) FROM table) LIMIT 1;
Don't forget to add index on date. If it's possible you add lot's of records at the same time you will have to add:
ORDER BY id DESC -- In case that date is highest for records for last records
ORDER BY time DESC -- Every other case
To the end of query
I am going to make the assumption that the record with the largest ID is the "last" (assuming strictly increasing sequential IDs that are unique within a table). If you have a better definition of "last" that could make a difference.
To get one "last" record, you could do:
Select * from table_1 where id = (select max(id) from table_1);
To get the results of all 50 tables into a single result set, you could do:
Select * from table_1 where id = (select max(id) from table_1)
union
Select * from table_2 where id = (select max(id) from table_2)
union
Select * from table_3 where id = (select max(id) from table_3)
union...
A MySQL-specific solution could be
Select * from table_1 order by id desc limit 1
union
Select * from table_2 order by id desc limit 1
union
Select * from table_3 order by id desc limit 1
union...
Based on your edit (where you actually define what you mean by "last"):
Select * from table_1 order by date desc, time desc, id desc limit 1
union
Select * from table_2 order by date desc, time desc, id desc limit 1
union
Select * from table_3 order by date desc, time desc, id desc limit 1
union...
Here is one way to do it without sorting the table:
select * from tab1
where time = (select max(time)
from tab1
where date = (select max(date) from tab1))
and date = (select max(date) from tab1)
It should be very fast, like, O(c), provided that both columns are indexed, otherwise the time will simply be O(n)