I have a table that contains 100000 rows and in that there is a column say drugname whose type is varchar.
The values of the column may start with 0 to 9 and
A-Z or a-z.
I need a query that returns 25000 rows. And out of that 25000 rows it should contain all the alphabets and numbers.
Say for example,
alphabet A contains 500 rows
alphabet B contains 500 rows
number 1 contains 400 rows
number 2 contains 300 rows etc...
that includes all the numbers and alphabets and overall it should have 25000 rows.
First select minimal set of ids for all the groups (by the first char)
select min(id) as substrId
from the_table
group by substr(value,0,1)
Then use the subselect to return the selected ids first (to represent all the groups) and then some random ids
select t1.*
from the_table t1
left join (select min(id) as substrId
from the_table
group by substr(value,0,1)) sub on t1.id=sub.substrId
order by ifnull(sub.substrId, 0) desc
limit 25000
Thus all the distinct group members are included in the final result set.
Enumerate the rows based on the first character. Then use the enumeration to get the rows:
select d.*
from (select d.*,
(#rn := if(#l = left(d.drugname, 1), #rn + 1,
if(#l := left(d.drugname, 1), 1, 1)
)
) as seqnum
from drugs d cross join
(select #rn := 0, #l := '') params
order by d.drugname
) d
order by seqnum
limit 25000;
Note: This returns the rows with the smallest drug names for each letter. If you want random ones, then use this order by:
order by left(d.drugname, 1), rand()
Related
I have a query that return the following table:
P_id S_id Time
1 "20" A 15
2 "30" B 50
3 "50" A 99
4 "70" A 60
I want to group the table, based on the column "Sid", and sorted by Column "Time" so it will look like this:
P_id S_id
1 "20","70","50" A
2 "30" B
What is the best way to do this by changing the SQL query?
When trying just to add "GROUP BY S_id" I get the error:
SELECT list expression references column query which is neither grouped nor aggregated at [2:16]
(Meaning it doesn't know how to group the values of P_id (all strings)
I think you want:
select s_id, group_concat(p_id order by time) as p_ids
from t
group by s_id;
If you want a first column that has numbers, you can add that in:
select (#rn := #rn + 1) as seqnum, s_id, group_concat(p_id order by time) as p_ids
from t cross join
(select #rn := 0) params
group by s_id;
select group_concat(P_id,',') from tablename group by S_id ;
I have really different problem about database query. There is a little bit different scenarios:
I have a table created with 3 columns. They have ID, ItemId, TypeId columns. I need a count query, it should count ItemId and TypeId together but except duplicate columns. For example;
Id ItemId TypeId
-- ------ ------
1 1 1 -> count +1
2 1 1 -> ignore
3 1 2 -> count -1
4 1 2 -> ignore
5 1 1 -> count +1
result count = 1
In the end, if distinct row repeated, count ignore that row. But TypeId data changed for one specific Item it should increase or decrease count. TypeId equals to 1 count +=1, equals to 2 count -=1.
In MySQL, you would seemingly use count(distinct):
select count(distinct itemId, typeId)
from t;
However, you really have a gaps-and-islands problem. You are looking at the ordering to see where things change.
If I trust that the id has no gaps, you can do:
select count(*)
from t left join
t tprev
on t.id = tprev.id + 1
where not ((t.itemId, t.typeid) <=> (tprev.itemId, t.prev.id))
Try the following query. This employs User-defined session variables. It will work in all the cases (including gaps in Id):
SELECT
SUM(dt.factor) AS total_count
FROM
( SELECT
#factor := IF(#item = ItemId AND
#type = TypeId,
0,
IF(TypeID = 2, -1, 1)
) AS factor,
#item := ItemId,
#type := TypeId
FROM your_table
CROSS JOIN (SELECT #item := 0,
#type := 0,
#factor := 0) AS user_init_vars
ORDER BY Id
) AS dt
DB Fiddle DEMO
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)
I have a query which aims to retrieve a random row from a result set. I do not want to use ORDER BY Rand() as it seems to be rather inefficient.
My method is as follows:
generate a single random number between [0,1)
give each row of the result query a unique 'rank' number. i.e. give the first row a value 1, second row a value 2, and so forth
use the random number to get a number between 1 and the number of rows in the result
return the row where rank == the number generated from the random number
example query:
SELECT * FROM(
(SELECT #rand := RAND(), #rank := 0) r1
CROSS JOIN
(SELECT (#rank:=#rank+1) as num, A.id FROM
A JOIN B
ON A.id = B.id
WHERE B.number = 42
)
WHERE num = FLOOR(1 + #rand * #rank) LIMIT 1
This works for retrieving one row, but I instead want 10 random rows. Changing LIMIT 1 to LIMIT 10 doesn't work, because if num + 10 > number of rows the query doesn't return 10 rows.
The only solution I can think of it to either generate 10 random numbers in the sql query, check they are all different from each other and have several WHERE num = random_number_1 lines. Alternatively, I could call the query 10 times, checking that the rows selected are unique. I wouldn't know how to do the former, and the latter seems like it is rather inefficient. Unless there is likely to be some wonderful cache that would make running the same query extremely fast?
Does anyone have any ideas? thank you
You could try the following:
select sq2.c1
from ( select *
from (select #count := 0) sq0
cross join
(select t1.c1, #count := #count+1
from t t1
join t t2
using(c1)
where t2.c2 = 42
) sq1
) sq2
--use a probability to pick random rows
where if(#count <= 5, 1, floor(1 + rand() * (#count-1))) <= ceiling(log(pow(#count,2)))+1
limit 5;
The results will be random unless the result set is smaller (or the same size as) the limit. If this is a problem, you can wrap the whole thing:
select sq3.* from ( select ... limit 5 ) sq3
order by rand().
This will only randomize the small number of output rows (at most 5) which is efficient.
Of course, you can always use a temporary table:
create temporary table rset (row_key int auto_increment, key(row_key))
as ( select .... where c2 = 42 ) engine=myisam;
set #count := select count(*) from rset;
select rset.c1
from rset
where row_key in ( (floor(1 + rand() * (#count-1))),
(floor(1 + rand() * (#count-1))),
(floor(1 + rand() * (#count-1))),
(floor(1 + rand() * (#count-1))),
(floor(1 + rand() * (#count-1))) );
drop table rset;
If you want to guarantee that you get five unique rows, then you can use a second temporary table:
create temporary table row_keys ( row_key int not null primary key );
-- do this successful five times. if you get a unique key error try again
insert into row_keys values (floor(1 + rand() * (#count-1));
select rset.c1
from rset
join row_keys
using(row_key);
I wanted to limit my query per category, I've seen a lot of same topic here but too complicated so I will ask another.
for example I have
id title category
1 one number
2 two number
3 three number
4 four number
5 a letter
6 b letter
7 c letter
and I wanted to limit my query, let say 2 per category so I have on my output like these
one
two
a
b
I got answer from diff topic
I'll post it here for others who will drop in this same question
SELECT * FROM (
SELECT
table.*,
#rn := CASE WHEN #category=category THEN #rn + 1 ELSE 1 END AS rn,
#category := category
FROM table, (SELECT #rn := 0, #category := NULL) AS vars
ORDER BY category
) AS T1
WHERE rn <= 2
Created using this link, there's an explanation there. This also works for a large number of categories, but beware, it can become very slow without the right keys defined.
set #num := 0, #category := '';
select title, category, #num := if(#category = category, #num +1, 1) as row_number,
#category := category as dummy
from test
group by category, title
having row_number <=2;
Tell me if i'm getting you right -
That's the sql -
SELECT * FROM `categories` ORDER BY `id` ASC LIMIT 0,2
What I did is this: Select all the items in categories table and order it by the id row, limit it for two results only and order it from the beggining