Alternative to max query? - mysql

Here is the database I'm using: https://drive.google.com/file/d/1ArJekOQpal0JFIr1h3NXYcFVngnCNUxg/view?usp=sharing
I'm trying to find out how I could return the research interest(descrip) with the largest number of interested academics(acnum) without the use of MAX query or ouputting descending order.
Each academic has a unique acnum, so I'm trying to link it with research interest(descrip) without having duplicate acnums.
I tried this:
SELECT x.descrip,
x.name_count
FROM (select u.descrip,
count(*) as name_count,
rank() over (order by count(*) desc) as rank
FROM interest u
WHERE u.descrip IS NOT NULL
GROUP BY u.descrip) x
WHERE x.rank = 1;
It partly works, but the acnums are duplicates, I want it to count distinct acnums.
Thank you

Related

sql - Is there a way to filter through the results of a SELECT query, with another SELECT query?

Specifically, what I am trying to do is rank a table by a column value, referred here as power, and then take that ranked table and find a specific row, or a user in this case. Much like what would be done in a video game leaderboard to find the ranking of a specific user.
Basically, I would like to find a specific row in a table that has been ordered. I know how to do both, but not together.
I guess what I'm trying to do is combine these statements:
Sorting:
SELECT * FROM users ORDER BY power DESC;
Filtering:
SELECT * FROM otherQueryResult WHERE discordID = discordIDInput;
And then find out the row number of the row that is returned.
Realistically, I'd like to have a result that looks something like this:
+-----------+------+
| discordID | rank |
+-----------+------+
| 123456789 | 52 |
+-----------+------+
Being 14, my SQL knowledge is still very limited - so I would prefer simpler solutions over raw performance or usability at the moment, however any help is appreciated.
Thanks in advance for any help.
You seem to be looking for a window function such as RANK():
SELECT *
FROM (SELECT u.*, RANK() OVER(ORDER BY power DESC) rnk FROM users u) x
WHERE discordID = ?
The inner query assigns a rank to each user, with the user having the highest power ranked first. Then, the outer query filters the user that has the relevant discordID.
There are other window functions that can respond to your use case:
ROW_NUMBER(): assigns a rank to each record ; even-records are not treated consistently
RANK(): even-records get the same rank ; if two users have rank 1, then the following user has rank 3
DENSE_RANK(): same as RANK(), but does not create gaps in the ranks
Join the tables and then rank.
select discordid, RANK() OVER
(PARTITION BY u.userid ORDER BY (the column that you are ranking from) DESC) AS Rank from otherqueryresult as q inner join user as u on u.id=q.userid
You can do the calculation directly.
I think you want:
select 1 + count(*)
from users u
where u.power > (select u2.power from users u2 where u2.discordID = ?);
You do not actually need window functions for this purpose. With indexes on (discordId, power) and (power) this should have very very good performance.

How to Insert Data into Tempdb Until Amount of Distinct Values Met

I have a main table named tblorder.
It contains CUID(Customer ID), CuName(Customer Name) and OrDate(Order Date) that I care about.
It is currently ordered by date in ascending order(ex. 2001 before 2002).
Objective:
Trying to retrieve most recent 1 Million DISTINCT Customer's CUID and CuNameS, and Insert them Into a Tempdb(#Recent1M) for Later Joining Uses.
So I:
Would Need Order By desc to flip the date to retrieve most recent 1 Million Customers
Only want first 1 Million DISTINCT Customer Information(CUID, CuName)
I know following code is not correct, but it is the main idea. I just can't figure out the correct syntax. So far I have the While Loop with Select Into as the most plausible solution.
SQL Platform: SSMS
Declare #DC integer
Set #DC = Count(distinct(CUID)) from #Recent1M))
While (#DC <1000000)
Begin
Select CuID,CuName into #Recent1MCus from tblorder
End
Thank you very much, I appreciate any help!
TOP 1000000 is the way to go, but you're going to need an ORDER BY clause or you will get arbitrary results. In your case, you mentioned that you wanted the most recent ones, so:
ORDER BY OrderDate DESC
Also, you might consider using GROUP BY rather than DISTINCT. I think it looks cleaner and keeps the select list a select list so you have the option to include whatever else you might want (as I took the liberty of doing). Notice that, because of the grouping, the ORDER BY now uses MAX(ordate) since customers can presumably have multiple ordate's and we are interested in the most recent. So:
select top 1000000 cuid, cuname, sum(order_value) as ca_ching, count(distinct(order_id)) as order_count
into #Recent1MCus
from tblorder
group by cuid, cuname
order by max(ordate) desc
I hope this helps.
Wouldn't you just do this?
select distinct top 1000000 cuid, cuname
into #Recent1MCus
from tblorder;
If the names might not be distinct, you can do:
select top 1000000 cuid, cuname
into #Recent1MCus
from (select o.*, row_number() over (partition by cuid order by ordate desc) as seqnum
from tblorder o
) o
where seqnum = 1;
Use DISTINCT and ORDER BY <colname> DESC to get latest unique records.
Try this SQL query:
SELECT DISTINCT top 1000000
cuid,
cuname
INTO #Recent1MCus
FROM tblorder
ORDER BY OrDate DESC;

JOIN, ORDER BY and GROUP BY in same statement

I have two tables - results and contestants. Result table cointains
result_id (PK)
resul_contestant (who scored this)
value (how much did he scored)
result_discipline(where he scored this)
contestants table cointains
contestant_id (PK)
contestant_name
contestant_category
What I want to do is to select results for all contestants, but I only want to show one result per contestant - the highest (lowest) one.
So far I managed to do this:
SELECT * FROM contenstants
JOIN results ON result_contestant = contenstant_id
WHERE result_discipline = 1 AND contestant_category = 1
ORDER BY value DESC
GROUP BY contenstant_id;
However, this gives me syntax error. If I delete the GROUP BY line, I got results ordered from highest, but if any of the contestants scored in this discipline more than once, I got all of his scores.
If I delete the ORDER BY line, I got only one result per contestant, but it returns the first record in db, not the highest one.
How to fix this command to be valid? Also, there are some less_is_better disciplines, where I want the lowest score, but as far as I could use the ORDER BY on final query, it should be achieved by replacing DESC with ASC.
Thanks.
Don't use group by. Using select * with group by just doesn't make sense. Instead, use a filter to get the row you want:
SELECT *
FROM contenstants c JOIN
results r
ON r.result_contestant = c.contestant_id
WHERE r.result_discipline = 1 AND c.contestant_category = 1 AND
r.value = (select min(r2.value)
from results r2
where r2.result_contestant = r.result_contestant and
r2.result_discipline = r.result_discipline
)
ORDER BY value DESC;
Note: I'm not sure if you want min() or max() in the subquery.

SELECT count(*) with ORDER BY

I want to ask you, if its correct if i use this ORDER BY in a SELECT COUNT(*)
Orginal: SELECT count(*) AS cnt FROM players WHERE totalpoints>?
Modified: SELECT count(*) AS cnt FROM players WHERE totalpoints>? ORDER BY timeontheserver DESC
In the Orginal query it outputs the players given "rank" in the database.
But i just noticed that some "players" are having the same amount of points and they get kinda reversed. So it should kinda give the player with an higher amount of "timeontheserver" the better "rank".
I hope you could understand this, thank you.
COUNT(*) will give you a number, you'll want to do a group by on the field you're ordering by to get what you want.
SELECT timeontheserver ,count(*) AS cnt FROM players
WHERE totalpoints>? GROUP BY timeontheserver ORDER BY timeontheserver DESC

I want to use max and count aggregate functions together in mysql query

I am using mysql 5.0.51b.
I have one table named xyz.
xyz table has a columns abc,location,pqr and lmn
Everytime an information is sent to particular location, its entry is done in xyz table.
I want to have the name of the location to which maximum information is sent.
The way i tried:
First of all i count the number of entries sent to each location using count and group by.
Now, the problem is to have the name(s) of the location with maximum values.
I have used temporary solution:
I use order by clause and limit to get the first record that has max values.
But this has one problem
If two locations has same count then above solution will give only one location and the other with same count will not be returned.
I want to solve this problem
Any hint will be very helpful
Thanks in anticipation
Thank you very much to everyone who has responded to my question and spared time to solve my problem.
However, i have got the solution:
SELECT count( * ) AS cnt2, location
FROM sms
GROUP BY location
HAVING cnt2 = (
SELECT count( * ) AS cnt
FROM sms
GROUP BY location
ORDER BY cnt DESC
LIMIT 1 );
very important hint on http://lists.mysql.com/mysql/203074
The inner query gives you the max count and outer query compares each count with max count.
Select MAX(cnt.Total) from
(select count( Name)as Total from Gk_RegUser_answer_rel group by Reg_UserId) As cnt
Try this interesting solution -
SELECT x.* FROM xyz x
JOIN (
SELECT GROUP_CONCAT(location) locations FROM (
SELECT location, COUNT(*) cnt FROM xyz GROUP BY location ORDER BY COUNT(*)) t
GROUP BY cnt DESC
LIMIT 1
) t
ON FIND_IN_SET(x.location, t.locations);
SELECT COUNT(*), `location` FROM `xyz` GROUP BY `location`
Above query will give you the information count to a specific location.
If this is not what you were looking for, can you provide some sample data and expected output?