Make MIN() return multiple rows? - mysql

Is there a way to return more than one row based on the idea of this query:
SELECT MIN(colname) AS value FROM table_name
Thanks
Dave

If you're trying to select the rows with the N (say, 10) smallest values in some column, you could do something like:
SELECT * FROM table_name ORDER BY colname ASC LIMIT 10;
Apologies if I've misunderstood the question.

No, there is no way to return more than 1 rows for this very query (the one you included in the example)
If you want to be doubly sure, add a "LIMIT 1" at the end. (that would limit the result set to 1 row, but not required here)
EDIT:
To answer your question "Is there any other query that can return say 5 rows based on each row having MIN values in one column", yes there is. You need to use a 'group by' syntax, for example:
SELECT category, MIN(price) AS value FROM table_name group by category

To select multiple rows one solution is to find all rows with values that match the previously determined minimum value:
SELECT *
FROM tableA
JOIN
(SELECT MIN(colname) AS minvalue FROM tableA) B
ON tableA.colname = B.minvalue
This solution differs from GROUP BY in that it will not otherwise aggregate (or limit) the data in the resultset. In addition, this particular solution does not consider the case of NULL being the "minimum value".
Happy coding.

Related

Limiting the count query in MySQL?

I am trying to do a simple test where I'm pulling from a table the information of a specific part number as such:
SELECT *
FROM table_name
WHERE part_no IN ('abc123')
This returns 25 rows. Now I want to count the number that meet the "accepted" condition in a specific column but the result is limited to only the 10 most recent. My approach is to write it as follows:
Select Count(*)
FROM table_name
WHERE part_no IN ('abc123') AND lot IN ('accepted')
ORDER BY date DESC
LIMIT 10
I'm having a hard time to get the ORDER BY and LIMIT operations to work. I could use help just getting it to limit appropriately, and I can figure out the rest from there.
Edit: I understand that the operations are happening on the COUNT which only returns one row with a value; but I put the second clip to show where I am stuck in my thought process.
Your query SELECT Count(*) FROM ... will always return exactly one row.
It's not 100% clear what exactly you want to do, but if you want to know how many of the last 10 have been accepted, you could use a subquery - something like:
SELECT COUNT(*) FROM (
SELECT lot
FROM table_name
WHERE part_no IN ('abc123')
ORDER BY date DESC
LIMIT 10
)
WHERE lot IN ('accepted')
The inner query will return the 10 most recent rows for part abc123, then the outer query will count the accepted ones.
There are also other solution (for example, you could have the inner query output a field that is 0 when the part is not accepted and 1 when the part is accepted, then take the sum). Depending on which exact dialect/database you are using, you may also have more elegant options.
Select count returns ONE ROW therefore the ORDER BY and the LIMIT will not work on the results

In MySQL, how to retrieve records after/before a record with a given ID?

As part of implementing a GraphQL API I'm attempting to provide before/after pagination. For example, to return LIMIT records that come after a record with a given ID. This has to work on an arbitrary SELECT statement with arbitrary JOIN, WHERE and ORDER BY clauses already in place.
The benefit of this kind of pagination over just using page numbers is that it can more closely return an expected page of results when the underlying data is changing.
If I can get this working for after I can also make it work for before by inverting the ORDER BY clause, so here I'll focus just on the after condition.
What's the easiest or most efficient way to modify a given SELECT statement to accomplish this?
My first thought was to add an AND condition to the WHERE clause restricting results to those with column values from the ORDER BY clause that are greater than or equal to their values in the record with the given ID. But this doesn't seem to work, because there is no expectation of uniqueness in the ORDER BY clause columns, so there's no way to know where the target record will fall in the results, and therefore no way to know how to set the LIMIT to return the correct number of records.
Another approach is to first discover the offset of the target record within the initial SELECT statement, and then to add a LIMIT offset+1, limit clause to the initial SELECT statement with the discovered offset.
MySQL has no row_count() function or similar, but row numbers can be added like this:
SELECT #rownum:=#rownum+1 ‘rank’, t.*
FROM my_table t, (SELECT #rownum:=0) r ORDER BY field2;
Then the above can be used as a subquery to fetch the rank of the target record, e.g.
SELECT rank FROM (SELECT #rownum...) WHERE id = 42
And then using that rank as the offset for the final query:
SELECT ... LIMIT (rank + 1), 100
Possibly this can be done as a single query with multiple subqueries, e.g.
SELECT ... LIMIT (SELECT rank from (SELECT #rownum...) ...) + 1, 100
But this three query approach seems like an elaborate and not very rapid way to perform a very frequently used operation, putting a higher load on our database servers than we would prefer.
Is there a better way to do this?
Edit: A specific example was requested. Say I want to get a page of 2 articles from a table of 10 articles. We'll paginate this query:
select id, title from articles order by title desc
The table:
id, title
1, "a"
3, "b"
4, "c"
6, "d"
7, "e"
8, "f"
9, "g"
10, "h"
11, "i"
12, "k"
So when requesting the page after id 6 the correct records would be 4, "c" and 3, "b". This needs to work for arbitrary WHERE and ORDER BY clauses.
Without any actual examples tables, the following query is a blueprint of sorts to use.
It selects the rows from a table where a column value is greater than the row in the sub-query.
The sub-query selects the target row in the table that is the "starting point" for the rows desired.
In the example below, col1 is the ranking column. Change the WHERE clause in the sub-query to whatever would be needed to select the starting point row.
For pagination, alter the LIMIT clause to represent the previous pagination query.
SELECT
col1,
col2,
etc
FROM table a
JOIN (
SELECT col1
FROM table c
WHERE conditions
LIMIT 20,1
) b
ON a.col1 > b.col1
ORDER BY col1
LIMIT 20;
You can simply select the rows before or after you target row based on whatever you are ordering by. Assuming you have an index on id this should only require a single relatively inexpensive subquery:
SELECT id, title
FROM articles
WHERE title < (SELECT title FROM articles WHERE id = '6')
ORDER BY title DESC
LIMIT 0,2;
Next set would be
LIMIT 2,2
Previous set would require >= operator:
SELECT id, title
FROM articles
WHERE title >= (SELECT title FROM articles WHERE id = '6')
ORDER BY title DESC
LIMIT 0,2;
etc...
It would be easier to give a more succinct answer with more specific data and table structures but hope this helps.

Subquery returns more than 1 row solution for update query using select statement

Hello i have query in which i have written update statement using select statement. But unfortunately getting errors subquery returns more than 1 row. I know where the error is coming. But i dont know solution for the same.Thank you.
Here is the query:
UPDATE adsetest.dashboard_widget_users
SET configuration=
(SELECT DISTINCT ad_news_texte.headline
FROM autodo.ad_news_texte
INNER JOIN autodo.ad_news_oe
ON ad_news_texte.news_id = ad_news_oe.id_ad_news
INNER JOIN autodo.ad_news
ON ad_news_oe.id_ad_news = ad_news.id
WHERE ad_news.datum_archiv BETWEEN
curdate() - INTERVAL DAYOFWEEK(curdate()) + 28 DAY AND curdate())
WHERE dsnr_yw_user = 1 AND dsnr_dashboard_widget = 1
When you use update with SET configuration=(SELECT ...) the subquery has to return no more than one value (one row). If it returns more than one value how do you assign two rows table for example to scalar configuration field. So you should figure out WHY your subquery returns more than one row and fix the subquery or decide which ONE value to select for update in case of more than one row. For example you can select maximum value
SELECT MAX(ad_news_texte.headline)...
or any one first value
(SELECT ad_news_texte.headline)... LIMIT 1)
and so on...
If you need to concatenate all rows and put it into one row configureation you can use GROUP_CONCAT() mysql function:
SET configuration=(SELECT GROUP_CONCAT(DISTINCT ad_news_texte.headline) FROM ....
You have to first think about what you want to do.
Do you want to fetch one value and save it somewhere else?
Then use SET value = (SELECT...). For this you need to make sure, the inner statement doesn't return more than one value.
Or
Do you need to be able to handle fetching multiple values?
What do you want to do with these? Save all of them? All in one (use concat) or store them individually (one update per result)? Or select one of them? Maybe the first (LIMIT 1) or highest (MAX) or lowest (MIN) value?

Multiple counting in 1 sql statement

Lets say I have a table with a column of ages..
Here is the list of ages
1
2
3
1
1
3
I want the SQL to count how many of age 1s, how many of 2s and 3s.
The code:
Select count(age) as age1 where age = ‘1’;
Select count(age) as age2 where age = ‘2’;
Select count(age) as age3 where age = ‘3’;
Should work but would there be a way to just display it all using only 1 line of code?
This is an instance where the GROUP BY clause really shines:
SELECT age, COUNT(age)
FROM table_name
GROUP BY age
Just an additional tip:
You shouldn't use single quotes here in your query:
WHERE age = '1';
This is because age is an INT data type and therefore does not have single quotes. MySQL will implicitly convert age to the correct data type for you - and it's a negligible amount of overhead here. But imagine if you were doing a JOIN of two tables with millions of rows, then the overhead introduced would be something to consider.
Try this ,if the count is limited to three ages ,also using aggregate functions without grouping them will result in a single row,you can use SUM() with the condition which will result in a boolean and you can get the count based on your criteria
Select SUM(age = '1') as age1,
SUM(age = '2') as age2,
SUM(age = '3') as age3
from table
SELECT SUM(CASE WHEN age = 1 THEN 1 ELSE 0 END) AS age1,
SUM(CASE WHEN age = 2 THEN 1 ELSE 0 END) AS age2,
SUM(CASE WHEN age = 3 THEN 1 ELSE 0 END) AS age3
FROM YourTable
If your query should return only one column (age in this case, you can use Count+groupby):
SELECT age, Count(1) as qty
FROM [yourTable]
GROUP BY age
Remember you must include any additional column in your group by condition.
Select age as Age_Group, count(age) as Total_count from table1 group by age;
select age, count(age) from SomeTable group by age
http://sqlfiddle.com/#!2/b40da/2
The group by clause works like this:
When using aggregate functions, like the count function without a group by clause the function will apply to the entire dataset determined by the from and where clauses. A count will for instance count the number of rows in the result set, and sum over a specfic column will sum all the rows in the result set.
What the group by clause allows us to do, is to divide the result set determined by the from and where clause into partitions, so that the aggregate functions no longer applies to the result set as a whole, but rather within each partition of the result set.
When you specify a column to group by, what you are saying is something like "for each distinct value of column x in the result set, create a partition containing any row in the result set with this particular value in column x". Then, instead of yielding one result covering the entire resultset, aggregate functions will yield one result for each distinct value of column x in the result set.
With your example input of:
1
2
3
1
1
3
let's analyze the above query. As always, we should look at the from clause and the where clause first. The from clause tells us that we are selecting from SomeTable and only this, and the lack of a where clause tells us that we are selecting from the full contents of SomeTable.
Next, we'll look at the group by clause. It's present, and it groups by the age column, which is the only column in our example. The presence of the group by clause changes our dataset completely! Instead of selecting from the entire row set of SomeTable, we are now selecting from a set of partitions, one for each distinct value of the age-column in our original result set (which was every row in SomeTable).
At last, we'll look at the select-clause. Now, since we are selecting from partitions and not regular rows, the select-clause has fewer options for what it can contain, actually it only has 2: The column that it is grouped by, or an aggregate function.
Now, in our example we only have one column, but consider that we had another column, like here:
http://sqlfiddle.com/#!2/d5479/2
Now, imagine that in our data set we have two rows, both with age='1', but with different values in the other column. If we were to include this other column in a query that is grouped by the age-column (which we now know will return one row for each partition over the age-column), which value should be presented in the result? It makes no sense to include other column than the one you grouped by. (I'll leave multiple columns in the group by clause out of this, in my experience one usually just wants one..)
But back to our select-clause, knowing our dataset has the distinct values {1, 2, 3} in the age-column, we should expect to get 3 rows in our result set. The first thing to be selected is the age-column, which will yield the values [1, 2, 3]´ in the three rows. Next in theselect-list is an aggregate functioncount(age), which we now know will count the number of rows in each partition. So, for the row in the result whereage='1', it will count the number of rows withage='1', for the row whereage='2'it will count the number of rows whereage='2'`, and so on.
The result would look something like this:
age count(age)
1 3
2 1
3 2
(of course you are free to override the name of the second column in the result, with the as-operator..)
And that concludes today's lesson.

Select most common value from a field in MySQL

I have a table with a million rows, how do i select the most common(the value which appears most in the table) value from a field?
You need to group by the interesting column and for each value, select the value itself and the number of rows in which it appears.
Then it's a matter of sorting (to put the most common value first) and limiting the results to only one row.
In query form:
SELECT column, COUNT(*) AS magnitude
FROM table
GROUP BY column
ORDER BY magnitude DESC
LIMIT 1
This thread should shed some light on your issue.
Basically, use COUNT() with a GROUP BY clause:
SELECT foo, COUNT(foo) AS fooCount
FROM table
GROUP BY foo
ORDER BY fooCount DESC
And to get only the first result (most common), add
LIMIT 1
To the end of your query.
In case you don't need to return the frequency of the most common value, you could use:
SELECT foo
FROM table
GROUP BY foo
ORDER BY COUNT(foo) DESC
LIMIT 1
This has the additional benefit of only returning one column and therefore working in subqueries.