i have a table with around 1 128 910 rows and now my SQL statement is starting to run very slow.
My table looks like this:
SU_Id SU_User SU_Skill SU_Value SU_Date
int(10) int(10) int(10) float int(10)
1 1 23 45.34 1300978612
2 1 23 48.51 1300978865
3 1 23 47.21 1300979203
4 3 23 61.01 1300979245
5 2 23 38.93 1300979412
6 1 17 12.76 1300979712
7 2 23 65.30 1300979998
As seen in SU_Skill a user can have more then one entry with the same skill number. SU_Value hold the value of a skill, it can go up and down. SU_Date holds the date when a value was added.
I want a SQL statement that selects the 20 currently highest values of a skill. The following SQL statement is what i use today but it is slow and i think there is a better way of doing it.
SELECT DISTINCT SU_User AS Player,
(SELECT SU_Value FROM WOU__SkillUploads WHERE SU_User = Player AND SU_Skill = 23 ORDER BY SU_Date DESC LIMIT 1) AS Value
FROM WOU__SkillUploads
WHERE SU_Skill = 23
ORDER BY Value DESC LIMIT 20
Is there a faster way? Thanks for reading my question!
Sub-selects are very slow, especially in the way you're using this.
Rewrite this as a JOIN. In this case, because you want all records from SkillUploads where SU_SKILL = 23, this should probably be a RIGHT JOIN.
Can the same user be in the results multiple times? This may work for you.
SELECT SU_USER, MAX(SU_VALUE)
FROM WOU_SKILLUploads
WHERE SU_SKILL=23
GROUP BY SU_USER
ORDER BY MAX(SU_VALUE) DESC
LIMIT 20
Related
select producten_pid from prodsymp where symptomen_id = 11 and symptomen_id = 18;
I am trying the select statement above on a mysql table.
But I am not getting any results, where I should.
What am I doing wrong?
Thank you for your answers.
The idea was to create a database for problems and solutions,
where one problem can have multiple solutions and one solution can solve multiple problems.
I created this reference table 'probsol' with references to both the problems and the solutions table like below.
psid 1 2 3 4 5 6 7 8 9
pid 11 11 12 12 17 18 18 19 20
sid 18 9 18 10 10 18 9 13 13
Now I am trying to create a query to find lets say a single solution to multiple problems as below:
select sid from prodsymp where pid = 11 and pid = 12;
The results for this query should be 18, but I am getting 0 results.
Mysql is working as expected. You ask for a row where symptomen_id is at the same time 11 and 18. There can be no such row, so you don't get any result.
Maybe you wanted to use OR.
Your logic is wrong. symptomen_id can't be both at the same time. Use or.
Even better, use in like so:
select producten_pid from prodsymp where symptomen_id in (11, 18).
Edit:
Afer you edited your question, your problem became quite different.
Maybe this query can help:
SELECT
sid,
count(*) as cnt
FROM
producten_pid
where
pid in (
11,12
)
group by
sid
having
count(*) > 1
Well, I'm using MYSQL and I cannot specify specific columns multiple times. I know that the following code is wrong but it is to better understand what I am trying to do.
Note: id_follow_book = id book
I need to specify in the same query, from id_follow_book select some id in specific and with some specific chapters. With IN it does not help me, because I would select the id to follow the books well, but then I would not pick the correct chapters for each follow-up. Exist the possibility that the user is not following a book or id_follow_book, maybe even none. What I'm trying to return those that are followed by the user.
SELECT id_follow_book, num_chapt
FROM Follow, Chapters
WHERE id_user = 1 AND
id_follow_book = id_chapter_book AND
(id_follow_book = 15 AND num_chapt = (10+1)) AND/OR
(id_follow_book = 25 AND num_chapt = (5+1)) AND/OR
(id_follow_book = 30 AND num_chapt = (23+1))
The sum numbers are variables.
I tried too with CASE WHEN, but I didn't achieve it. Thanks and sorry for my english.
Follow Chapters
id_follow_book id_user id_chapter_book num_chapt
30 1 30 6
25 1 30 5
13 1 30 4
21 1 25 24
25 23
Expected result:
id_follow_book num_chapt (this is last viewed chapt of user, this solutioned)
30 6
25 24
Try using IN operator:
SELECT id_follow_book, num_chapt
FROM Follow inner join Chapters on
id_follow_book = id_chapter_book
WHERE id_user = 1 AND
id_follow_book in( 15,25,30) AND num_chapt in(11,6,24)
I'm just stuck with this issue atm and I'm not 100% sure how to deal with it.
I have a table where I'm aggregating data on week
select week(create_date),count(*)
from user
where create_date > '2015-02-01'
and id_customer between 9 and 17
group by week(create_date);
the results that I'm getting have missing values in the count, as shown below
5 334
6 376
7 394
8 405
9 504
10 569
11 709
12 679
13 802
14 936
15 1081
16 559
21 1
24 9
25 22
26 1
32 3
34 1
35 1
For example here from 16 to 21 there a obviously 4 values missing I would like these values to be included and count to be 0. I want this because I want the weeks to be matching with other metrics as we are outputting them in an excel file for internal analysis.
Any help would be greatly appreciated.
The problem is that an sql query cannot really produce data that is not there at all.
You have 3 options:
If you have data for each week in your entire table for the period you are querying, then you can use a self join to get the missing weeks:
select week(t1.create_date), count(t2.id_customer)
from customer t1
left join customer t2 on t1.id_customer=t2.id_customer and t1.create_date=t2.create_date and t2.id_customer between 9 and 17
where t1.create_date > '2015-02-01'
group by week(t1.create_date)
If you have missing weeks from the customer table as whole, then create a helper table that contain week numbers from 1 or 0 (depending on mysql config) to 53 and do a left join to this helper table.
Use a stored procedure that loops through the results of your original query and inserts the missing data in the resultset using a temporary table and then returns the extended dataset as result.
The problem is that there is no data matching your criteria for the missing weeks. A solution will be to join from a table that has all week numbers. For example if you create a table weeknumbers with one field weeknumber containing all the numbers from 0 to 53 you can use something like this
select weeknumber,count(user.*)
from weeknumbers left join user on (weeknumbers.weeknumber=week(user.create_date)
and user.create_date > '2015-02-01'
and user.id_customer between 9 and 17)
group by weeknumber;
Additionaly you might want to limit the week numbers you do not want to see.
The other way is to do it in the application.
Have a existing table of results like this;
race_id race_num racer_id place
1 0 32 2
1 1 32 3
1 2 32 1
1 3 32 6
1 0 44 2
1 1 44 2
1 2 44 2
1 3 44 2
etc...
Have lots of PHP scripts that access this table output the results in a nice format.
Now I have a case where I need to output the results for only certain race_nums.
So I have created this table races_included.
race_view race_id race_num
Day 1 1 0
Day 1 1 1
Day 2 1 2
Day 2 1 3
And can use this query to get the right results.
SELECT racer_id, place from results WHERE race_id=1
AND race_num IN
(SELECT race_num FROM races_included WHERE race_id='1' AND race_view='Day 1')
This is great but I only need this feature for a few races and to have it work in a compatible mode for the simple case show all races. I need to add alot of rows to the races_included table. Like
race_view race_id race_num
All 1 0
All 1 1
All 1 2
All 1 3
95% of my races don't use the daily feature.
So I am looking for a way to change the query so that if for race 1 there are no records in the races_included table it defaults to all races. In addition I need it to be close the same execution speed as the query without the IN clause, because this query Or variations of it are used a lot.
One way that does work is to redefine the table as races_excluded and use NOT IN. This works great but is a pain to manage the table when races are added or deleted.
Is there a simple way to use EXISTS and IN in tandem as a subquery to get the desired results? Or some other neat trick I am missing.
To clarify I have found a working but very slow solution.
SELECT * FROM race_results WHERE race_id=1
AND FIND_IN_SET(race_num, (SELECT IF((SELECT Count(*) FROM races_excluded
WHERE rid=1>0),(SELECT GROUP_CONCAT(rnum) FROM races_excluded
WHERE rid=1 AND race_view='Day 1' GROUP BY rid),race_num)))
It basically checks if any records exists for that race_id and if not return a set equal to the current race_num and if yes returns a list of included race nums.
You can do this by using or in the subquery:
SELECT racer_id, plac
from results
WHERE race_id = 1 AND
race_num IN (SELECT race_num
FROM races_included
WHERE race_id = '1' AND (race_view = 'Day 1' or raw_view = 'ANY')
);
I want to select some rows with a specific filter, but don't limit if I don't get, at least, 40 rows.
It's a pseudo-example:
SELECT * FROM `table`
WHERE
SUM(1) < 40 OR
`age` > 18
It's similar to LIMIT, but LIMIT will consider the WHERE filter ever. I want to ignore the filter if I don't have at least 40 rows (but accept the firsts rows).
How I do that?
Edit: a lot of people had doubts what I really wanted.
This is an example:
ID AGE
1 10
2 20
3 30
4 10
5 20
6 30
7 10
I want to get the first 2 rows EVER. And only after at least two rows, get new rows that match the given conditions (WHERE).
For example: I want the first 2 rows more rows whose age is 30. The result would be equivalent to:
ID AGE
1 10 <first>
2 20 <second>
3 30 <conditional>
6 30 <conditional>
You can use an increasing variable #rownum to simulate the same functionality. However, this is much less efficient than limit because the server brings the filtered-out rows into memory and continuously performs the #rownum:=#rownum+1 calculation.
SELECT #rownum:=#rownum+1, t.*
FROM `table` t, (SELECT #rownum:=0) r
WHERE
#rownum <= 40 OR
`age` > 18