MySQL - Select row number of a record - mysql

I have a table in MySQL populated as follows. Now I need to select the row number of a record in its sorted order. For example, the row number of words starting with 'c' should be 4.
Words
=====
coffee
banana
apple
cherry
blackberry
I tried the following query, but I get wrong results. Here dict is the table name and words is the column name.
SELECT #rownum:=#rownum + 1 id FROM (SELECT * FROM dict ORDER BY words) d,(SELECT #rownum:=0) r WHERE d.words LIKE CONCAT('c','%')
For the above query, I am getting the row numbers for the outer query. But I want the row numbers of the internal query. I do not know how to get that.
Any help is appreciated. Thanks.

Try this perhaps:
SET #rownum = 0;
SELECT id
FROM (SELECT *, #rownum:=#rownum + 1 AS id FROM dict ORDER BY words) d
WHERE d.words LIKE CONCAT('c','%')
As single query, try this:
SELECT id
FROM (SELECT *, #rownum:=#rownum + 1 AS id FROM dict, (SELECT #rownum:=0) r ORDER BY words) d
WHERE d.words LIKE CONCAT('c','%')

Related

SQL delete rows which have duplicate values for more than one column

I have a table with many columns and I want to delete the rows which have duplicate values for 7 columns and keep only the row which has the highest value on one of the other columns. My table looks like this:
I need to look at columns: minA, minB, minC, minD, minE, minF, minG and minH and where values are duplicates, I want to keep the row which has the highest "maxPercent".
Based on this, in my table I want to delete everything except for id 1 and id 5. id 2,3 and 4 are duplicates of 1 and 6 and 7 are duplicates for 5.
I have tried the below query for grouping the duplicate rows, but it did not get me the expected result:
select * from duplicates t1 where exists (select 1 from duplicates t2 " +
" where t1.minA = t2.minA and t1.minB = t2.minB and t1.minC = t2.minC and t1.minD = t2.minD and " +
"t1.minE = t2.minE and t1.minF = t2.minF and t1.minG = t2.minG and t1.minH = t2.minH and t1.id <> t2.id)
Can anyone help me with this?
If you can use the row_number function, the query looks like this:
delete from duplicates where id not in (
select id from (
select
id,
row_number() over(
partition by minA, minB, minC, minD, minE, minF, minG, minH
order by maxPercent desc) n
from duplicates
) d
where n=1
)
n is in descending order, so n=1 means each row with the maximum value.
DB Fiddle

Mysql group_concat split by count

Is it possible to perform a group_concat in mysql and have some sort of group limit? thus allowing the group to be split over a number of result rows?
e.g.
if I have a table called num like so:
val
---
1
2
3
4
5
...
and I use the statement select group_concat(val) from num
I get the result
1,2,3,4,5,...
What I want to do is set a group limit of 2 and get the result
1,2
3,4
5,...
Now the use case I have is hundreds of thousands of values that I want to select as neat groups of about 500.
Is it possible?
You can use a user variable to create a row number, then group by dividing the row numbers by the group size.
SELECT GROUP_CONCAT(val) AS vals
FROM (SELECT val, #rownum := #rownum + 1 AS rownum
FROM (SELECT val FROM nums ORDER BY val) AS vals
CROSS JOIN (SELECT #rownum := -1) AS vars) AS temp
GROUP BY FLOOR(rownum/500)

How to sort results from UNION

I have a query like this:
(select #number:=3)
union
(select #number:=2)
union
(select #number:=1)
order by #number ASC
With results:
3
2
1
But I would like the results in ascending order, like this:
1
2
3
How can I achieve the results in ascending order with a query like this?
You can wrap the UNION in a subquery, try this:
SELECT *
FROM(
SELECT #number := 3 AS number
UNION
SELECT #number := 2 AS number
UNION
SELECT #number := 1 AS number) tmp
ORDER BY number;
Here is an SQL Fiddle example.
An edit, to explain what is happening:
In your example, MySQL is treating each group as its own query (which is how you'd expect a union to work) so it is as if you had three different queries, and only the third one is being ordered.
So, by putting the unioned queries together, you have one result set, and that entire result set is what is being ordered.
This is your query:
(select #number:=3)
union
(select #number:=2)
union
(select #number:=1)
order by #number ASC
Your order by has a constant. It is order by "1" -- #number is a variable, not a column name. Hence, no ordering. What you want is to specify the number as a column name:
select 3 as number
union all
select 2
union all
select 1
order by number;
You should also use union all instead of union, unless you want the additional overhead of removing duplicates.

Get second smallest number(s) in sql column

I currently have the code below and it works for getting me the 2 smallest number, but I want to get all of the 2nd smallest numbers and link them to their name as opposed to just one of them. lets say the numbers in the tables was made up of this:
Name| number
----|------
w 2
a 8
s 2
e 2
z 3
I would want to get
w 2
s 2
e 2
and now I am just getting w 2
SELECT MAX(col) FROM table WHERE col NOT IN (SELECT MAX(col) FROM table);
If this code gets you the second smallest number (what you want):
SELECT MAX(col) FROM table WHERE col NOT IN (SELECT MAX(col) FROM table);
Then simply do:
select *
from table
where col = (SELECT MAX(col) FROM table WHERE col NOT IN (SELECT MAX(col) FROM table));
I didn't understand well, but if you're using LIMIT 1,1, you will only get 1 row or none.
Just use what #491243 commented on your question.
SELECT * FROM tablename WHERE number = (SELECT MIN(number) FROM tableName);
Forget it, now I understood the question.
Try this:
SELECT * FROM tablename WHERE number =
(SELECT number FROM tablename WHERE number !=
(SELECT MIN(number) FROM tablename) ORDER BY number LIMIT 1);
Hope this helps.
EDIT: Using the SQLFiddle table:
SELECT * FROM ships WHERE gunsize = (
SELECT gunsize FROM ships WHERE gunsize !=
(SELECT MIN(gunsize) FROM ships) ORDER BY gunsize LIMIT 1);
http://sqlfiddle.com/#!2/9ca94/11
SELECT name,(SELECT MAX(gunsize) FROM ships s2
WHERE s2.Name=s.name and gunsize not in (select max(gunsize) from ships))as gunsizes
FROM ships s
Something like this?

mysql select rows with same ids and preserve their order?

just a quick question:
i have to have one single query that has multiple rows - some rows are identicle - and the order of rows must be preserved in the result -
some idea of what im refering to:
SELECT id,date
FROM items
WHERE id IN (1,2,1,3)
ORDER BY id=1 DESC,id=2 DESC,id=1 DESC,id=3 DESC;
unfortunately mysql result is this:
1,2,3
not 1,2,1,3
it removes the duplicate which i have to have in my result to display in multiple panels on the same webpage -
i really dont want to loop thru each id one by one to get them the way i want to display -
is there a way to actually have one single query that will preserve the order and pull out rows based on request whether its unique or not -
Your query as it stands will never work, because duplicate values in a list of values of an IN clause are ignored. The only way to make this work is by using UNION ALL:
SELECT id, date FROM items where id = 1
UNION ALL
SELECT id, date FROM items where id = 2
UNION ALL
SELECT id, date FROM items where id = 1
UNION ALL
SELECT id, date FROM items where id = 3;
But to be frank, I suspect your data model so far past screwed it's unusable.
try
SELECT
id,
date
FROM items
WHERE id IN (1,2,1,3)
ORDER BY FIND_IN_SET(id, '1,2,1,3')
Another scrupulous way to answer a suspicious question:
SELECT
items.id,
items.date
FROM
items
JOIN
( SELECT 1 AS id, 1 AS ordering
UNION ALL
SELECT 2, 2
UNION ALL
SELECT 1, 3
UNION ALL
SELECT 3, 4
) AS auxilary
ON
auxilary.id = items.id
ORDER BY
auxilary.ordering
Another approach (untested, but should give you the idea):
CREATE TEMPORARY TABLE tt (id INT, ai int unsigned auto_increment primary key);
INSERT INTO tt (id) VALUES (1), (2), (1), (3);
SELECT
id,
date
FROM items JOIN tt USING (id)
ORDER BY tt.ai;
keeps the given order.
If you want to include the records with id=1 and the order doesn't matter as long as you get them, you can split your query into two queries, one for (1,2,3) union all the other query for id=1 or just do:
... In (1,2)
Union all
... In (1,3)
Example:
Select * from
(Select case id when 1 then 1 when 2 then 2 as pseudocol, othercolumns
From table where Id in (1,2)
Union all
Select case id when 1 then 3 when 3 then 4 as pseudocol, othercolumns
From table where Id in (1,3)) t order by pseudocol
Instead of doing what you are trying to, just select the unique rows you need. In the frontend code, store each unique row once in a key=>value structure, where key is the item ID and value is whatever data you need about that item.
Once you have that you can use frontend logic to output them in the desired order including duplicates. This will reduce the amount of redundant data you are trying to select.
For example This is not usable code - exact syntax required depends on your scripting language
-- setup a display order
displayOrder= [1,2,1,3];
-- select data from database, order doesn't matter here
SELECT id,date
FROM items
WHERE id IN (displayOrder);
-- cache the results in a key=> value array
arrCachedRows = {};
for (.... each db row returned ...) {
arrCachedRows[id] = date;
}
-- Now output in desired order
for (listIndex in displayOrder) {
-- Make sure the index is cached
if (listIndex exists in arrCachedRow) {
echo arrCachedRows[listIndex ];
}
}
If you must persist in using UNION despite my warnings
If you go against the above recommendation and absolutely MUST have them back in 1 query in that order then add on an additional row which will enforce the row order. See below query where I use variable #subIndex to add an incrementing value as subIndex. This in turn lets you reorder by that and it'll be in the requested order.
SELECT
i.*
FROM (
SELECT #subIndex:=#subIndex+1 AS subIndex, id, date FROM items where id = 1
UNION
SELECT #subIndex:=#subIndex+1 AS subIndex, id, date FROM items where id = 2
UNION
SELECT #subIndex:=#subIndex+1 AS subIndex, id, date FROM items where id = 1
UNION
SELECT #subIndex:=#subIndex+1 AS subIndex, id, date FROM items where id = 3
) AS i,(SELECT #subIndex:=0) v
ORDER BY i.subIndex
Or a slightly cleaner version that keeps item selection until the outside and hides the subindex
SELECT
items.*
FROM items
-- initialise variable
INNER JOIN (SELECT #subIndex:=0) v
-- create a meta-table with the ids desired in the order desired
INNER JOIN (
SELECT #subIndex:=#subIndex+1 AS subIndex, 1 AS id
UNION
SELECT #subIndex:=#subIndex+1 AS subIndex, 2 AS id
UNION
SELECT #subIndex:=#subIndex+1 AS subIndex, 1 AS id
UNION
SELECT #subIndex:=#subIndex+1 AS subIndex, 3 AS id
) AS i
ON i.id = items.id
-- order by the subindex from i
ORDER BY i.`subIndex` ASC