Re-write a nested mysql query so as to create a view - mysql

I have a nested query. Any suggestion on how i can rewrite the nested query so that I am able to create a view with it
Here is the query
select *
from (select * from tracking_table order by id desc) x
group by labref);

There doesn't seem to be any need for the nested query. It can just be:
SELECT *
FROM tracking_table
GROUP BY labref
ORDER BY id DESC
But both queries probably don't do what you want. All the columns will be chosen from unpredictable rows in each group, and there's no guarantee that different columns will come from the same row. You're also not guaranteed to get the highest ID in each group.
If you want the row with the highest ID for each labref, see SQL select only rows with max value on a column

Related

MySQL 5.7 How to do GROUP BY with sorting?

Similar to this issue: MySQL 5.7 group by latest record
I'm not sure how to do this properly in 5.7. Also with possibility of 2nd sort column. Working query in 5.6 that I'm trying to replicate in 5.7:
SELECT id FROM test
GROUP BY category
ORDER BY sort1 DESC, sort2 DESC
id is not always the highest, so MAX(id) does not work.
Looking into the link above, the solution for single sort should be:
SELECT t1.*
FROM test t1
INNER JOIN (
SELECT category, max(sort) AS sort FROM test GROUP BY category
) t2 ON t2.category = t1.category AND t2.sort = t1.sort
But how will it work with 2 sorting?
You are using GROUP BY the wrong way.
Think of group by as a way to separate data row into different groups. Each group has multiple rows, based on the value of group by column.
Once you get those groups, selecting table columns (as in: select *) is like picking any row from that group randomly. This is not helpful nor useful.
Usually once we group records (or rows), we need to find meta information about those records. For example: get us the count of records in that group (as in: select count(*)), or the sum of values of a specific column in that group (as in: select sum(price)), or get the min, max or avg values.
So in a nutshell, when you use group by you should use on of the aggregation functions with it, otherwise it's not going to do you any good.
Why don't you have the ORDER BY at your outer query, instead?
SELECT *
FROM (
SELECT 100 AS id, 1 AS category, NULL AS sort
UNION
SELECT 200 AS id, 1 AS category, 2 AS sort
) dt
GROUP BY category
ORDER BY sort DESC;
It seems that what happened to the data when it was grouped, it took the first data while neglecting the ORDER BY DESC. On your first query, it ordered descending first then group by took the first record which is 200. And yes, this shouldn't be the way you should use GROUP BY. It is used in conjunction with aggregate functions.
when you select a column in a group by query that is not one of the columns you are grouping by, (ie, your id) you have no control over the value unless you use another aggregate function. If you want to sort, use MIN or MAX:
SELECT MAX(id), category, FROM `test2`
GROUP BY category; -- always returns 200
SELECT MIN(id), category, FROM `test2`
GROUP BY category; -- always returns 100

In MySQL, what does this simple nested SELECT clause mean exactly?

Here is the example from this thread:
select (
select distinct Salary from Employee order by Salary Desc limit 1 offset 1
)as second;
The select(...) as second looks confusing to me because I've never seen a query-set instead of column names can be used as the argument of SELECT..
Does anyone have ideas about how to understand nested select clause like this? Is there any tutorials about this feature?
That's a subquery in the SELECT list of a query.
To get there, let's look at some other examples
SELECT t.id
, 'bar' AS foo
FROM mytable
WHERE ...
LIMIT ...
'bar' is just a string literal that gets returned in every row (in a column named foo) in the resultset from the query.
Also, MySQL allows us to run a query without a FROM clause
SELECT 'fee' AS fum
We can also put a subquery in the SELECT list of a query. For example:
SELECT t.id
, (SELECT r.id FROM resorts r ORDER BY r.id ASC LIMIT 1) AS id
FROM mytable
WHERE ...
LIMIT ...
The query pattern you asked about is a SELECT statement without a FROM clause
And the only expression being returned is the result from a subquery.
For example:
SELECT e.salary
FROM Employee e
GROUP BY e.salary
ORDER BY e.salary DESC
LIMIT 4,1
If this query runs, it will return one column, and will return either one or zero rows. (No more than one.) This satisfies the requirements for a subquery used in a SELECT list of another query.
SELECT ( subquery ) AS alias
With that, the outer query executes. There's no FROM clause, so MySQL returns one row. The resultset is going to consist of one column, with a name of "alias".
For each row returned by the outer query, MySQL will execute the subquery in the SELECT list. If the subquery returns a row, the value of the expression in the SELECT list of the subquery is assigned to the "alias" column of the resultset. If the execution of the subquery doesn't return a row, then MySQL assigns a NULL to the "alias" column.

How to get unsorted result from a select query that uses an 'in'?

below is the query i have.
select * from tblQuestionTable where Paper='HTML' and QuestionId in (select QuestionId from tblTestOverview where TestId=1)
The sub query gives an unsorted result set, but the after querying the second select the result is sorted. How can i get the result in the same order as the subquery.
Any dataset your query is working with is by default unordered, whether it is a physical table or a derived one. Whatever order the server uses to read rows from it while actually executing the query is out of your control. That means you cannot reliably specify the order to be "same as in that subquery". Instead, why not just have a specific order in mind and specify it explicitly in the main query with an ORDER BY? For instance, like this:
SELECT *
FROM tblQuestionTable
WHERE Paper='HTML'
AND QuestionId IN (SELECT QuestionId FROM tblTestOverview WHERE TestId=1)
ORDER BY QuestionId
;
Having said that, here's something that might be close to what you are looking for. The ROW_NUMBER function assigns row numbers to the derived dataset in an undetermined order (ORDER BY (SELECT 1)). It may or may not be the order in which the server has read the rows, but you can use the assigned values to order the final result set by:
SELECT q.*
FROM tblQuestionTable AS q
INNER JOIN (
SELECT
QuestionId,
rn = ROW_NUMBER() OVER (ORDER BY (SELECT 1))
FROM tblTestOverview
WHERE TestId = 1
) AS o
ON o.QuestionId = q.QuestionId
ORDER BY o.rn ASC
;
select result for tblQuestionTable will be sorted based on its primary index by default unless specified. tblTestOverview select result also does the same. So you need to include the primary index key feild from tblTestOverview table in the select query for tblQuestionTable and specify an order by clause based on that field.

Is efficient the following SQL query?

Exist a better way to do what the following SQL query does? I have the feeling that table1 will be searched twice and may be that can be avoided with some trick and increase the efficient of the query, but I just can't figure out how ;( Here is the query (in MySQL):
SELECT a, SUM(count)
FROM table1
GROUP BY a
HAVING SUM(count) = (SELECT SUM(count) as total FROM table1 GROUP BY a ORDER BY total DESC LIMIT 1)
The goal is return the number(s) with the major accumulate, with its accumulate.
being table1 a two field table like:
a,count
1,10
1,30
1,0
2,1
2,100
2,4
3,10
4,50
4,55
The result with that data sample is:
2,105
4,105
Thanks in advance.
SELECT a, total FROM
(SELECT a AS a, SUM(COUNT) AS total
FROM table1
GROUP BY a) AS xyz
HAVING total = MAX(total)
Hope this will work for you
This sub-query is executed only once, and you don't have to bother with creating any pre-query as other answers may suggest (although doing so this is still correct, just not needed). Database engine will realise, that the sub-query is not using any variable dependent on the other part of the query. You can use EXPLAIN to see how the query is executed.
More on the topic in this answer:
https://stackoverflow.com/a/658954/1821029
I think you could probably do it by moving your HAVING sub-select query into its on prequery. Since it will always include a single row, you won't require any "JOIN", and it does not have to keep recomputing the COUNT(*) every time the HAVING is applied. Do it once, then the rest
SELECT
a,
SUM(count)
FROM
table1,
( SELECT SUM(count) as total
FROM table1
GROUP BY a
ORDER BY total DESC
LIMIT 1 ) PreQuery
GROUP BY
a
HAVING
SUM(count) = PreQuery.Total
This query return one row with two columns:
1- a list of comma separated values of "a" column, which have the biggest "Total"
2- and the biggest Total value
select group_concat(a), Total
from
(select a, sum(count) as Total
from table1
group by a) OnTableQuery
group by Total
order by Total desc
limit 1
Note that it queries table1 just one time. The query was already tested.

MySQL - using GROUP BY and DESC

In my SQL query I am selecting data with GROUP BY and ORDER BY clauses. The table has the same numbers across multiple rows with different times in each row. So I think I want to apply a GROUP BY clause.
However in the results return the oldest time with the number, but I need the most recent time.
SELECT * FROM TABLE GROUP BY (numbers) ORDER BY time DESC
The query appears as if it should first apply GROUP BY and then ORDER BY... but the results do not appear to work this way.
Is there any way to fix this?
SELECT *
FROM table t
WHERE time = (
SELECT max(time)
FROM table
WHERE t.numbers = numbers
)
work-around is to re-write the query as:
SELECT * FROM (SELECT * FROM table ORDER BY time DESC) AS t GROUP BY numbers;
SELECT * FROM table
WHERE time IN (
SELECT MAX(time)
FROM table
GROUP BY numbers
)
According to the manual you can add desc to the group by list:
Example:
group by item1, item2 desc, item3
with or without rollup.
I've tried this and it works in Ubuntu version 5.5.58. The reference page is:
https://dev.mysql.com/doc/refman/5.7/en/group-by-modifiers.html
SELECT * FROM TABLE GROUP BY numbers DESC;
This will give you last record from group.
Thanks