I have a mysql table like so:
Tbl
[Username Number Type]
manos 5 A
manos 6 B
maria 2 A
maria 3 B
maria 1 C
nick 7 A
nick 4 C
aaron 8 A
I want to create a view where I will have the ranks of each user (by larger Number), grouped by Type, in comparison to the other users in each Type. More specifically, I would like the output to be:
[Username Rank Type]
manos 3 A
manos 1 B
maria 4 A
maria 2 B
maria 2 C
nick 2 A
nick 1 C
aaron 1 A
I have tried the following:
select Username, count(*) as Rank, Type
from Tbl as aw
where
Number <= (
select Number
from Tbl
where Type = aw.Type
)
group by Username, Type
The result is that I get the Subquery returns more than 1 row error.
Any help would be appreciated!
Edit: changed the names of columns as suggested. Also a fiddle to help: http://sqlfiddle.com/#!9/55ec3f
Edit 2: Some clarification and corrections to the "all combinations rank".
Lets say we have another table called Teams:
Teams
[Username Team]
manos T1
manos T2
maria T1
maria T2
nick T1
nick T2
aaron T3
In this case I want to extract ranks on each combination of group(s) and Types, i.e. for Manos I would like:
Rank against people in T1 with type A
Rank against people in T2 with type A
Rank against people in T1 with type B
Rank against people in T2 with type B
Rank against people in T1 AND T2 with type A
Rank against people in T1 AND T2 with type B
For the sake of sanity, I renamed your group column...
SELECT username
, user_group
, number
, CASE WHEN #prev=user_group THEN #i:=#i+1 ELSE #i:=1 END rank
, #prev:=user_group
FROM my_table x
, (SELECT #prev:=null, #i:=0) vars
ORDER
BY user_group
, number DESC;
Correct code:
select Username, (select Number
from Tbl as t
where t.Type = aw.Type and t.Username = aw.Username) as Rank, Type from Tbl as aw where
Number <= (
select Number
from Tbl as t
where t.Type = aw.Type and t.Username = aw.Username
) group by Username, Type
Related
I have table bio
ID Name Country Address
1 Dan America A
2 Dan Japan B
3 Dan Canada C
4 Marcus China D
5 Kurtis Nepal E
6 Kurtis Mexico F
7 Jack Indonesia G
I need to select only one from the duplicate value of column "Name". I expect the result like this.
ID Name Country Address
1 Dan America A
4 Marcus China D
5 Kurtis Nepal E
7 Jack Indonesia G
I used this query
SET SESSION sql_mode = ( SELECT REPLACE ( ##sql_mode, 'ONLY_FULL_GROUP_BY', '' ) );
Select * from bio group by name;
Is there any other way without using SET SESSION sql_mode = ( SELECT REPLACE ( ##sql_mode, 'ONLY_FULL_GROUP_BY', '' ) ); since if i didn't use that, it return error.
I have tried answer with forpass answer but it run very slow. Here is the Explain query.
id select_type table type possible_keys rows filtered Extra
1 PRIMARY b ALL 1095012 100.00 Using where
2 DEPENDENT SUBQUERY t ALL PRIMARY,semua 1095012 3.33 Range checked for each record (index map: 0x3)
You can do it with NOT EXISTS:
SELECT b.*
FROM bio b
WHERE NOT EXISTS (
SELECT 1
FROM bio t
WHERE t.Name = b.Name AND t.ID < b.ID
)
It can be easily achieved in MySQL 8.0 using the ROW_NUMBER() OVER (PARTITION BY ) window function. But in 5.7 you have to emulate the same function with variables. Something like below.
SELECT ID, Name, Country, Address
FROM (
SELECT *, IF (#prev <> name, #rn: = 0, #rn),
#prev: = Name,
#rn: = #rn + 1 AS rn
FROM bio,
(SELECT #rn: = 0 ) rn,
(SELECT #prev: = '') prev
ORDER BY Address ASC
) t
WHERE rn = 1;
Alternatively you can use simple join to avoid mentioning the column names
SELECT b1.*
FROM bio b1
JOIN
(
SELECT Name, Min(ID) AS ID FROM bio
GROUP BY Name
) b2
ON b1.Name = b2.Name AND b1.ID = b2.ID;
type cost
A 10
A 11
A 12
B 10
B 10
I have this small sample table. I want to select data where the cost of the same type is different.So the expected outcome should be:
type cost
A 10
A 11
A 12
The cost for A is different so I need to select these "A" out.
So what is the "select" sentence?
Thanks for the replies. Actually my table is little more complex like this
type cost people
A 10 jack
A 11 frank
A 12 lucy
B 10 amy
B 10 tom
I need to select the data meet one of the requirements below:
Same type with different cost
Same type with people "amy"
So the outcome should be like :
type cost people
A 10 jack
A 11 frank
A 12 lucy
B 10 amy
B 10 tom
Select all of type A because the cost is different
Select all of type B because the people has "amy"
I have firgure out how to select for amy like this:
select type, cost, people
from table
where type in
(select type from table where people = 'amy')
I don't know how to combine these conditions.
SQL Fiddle
You can use EXISTS to look for another row with same type but other cost:
select t1.type, t1.cost
from tablename t1
where exists (select * from tablename t2
where t2.type = t1.type
and t2.cost <> t1.cost)
Or have a sub-query that returns type values having different costs, and join with that result:
select t1.type, t1.cost
from tablename t1
join (select type
from tablename
group by type
having max(cost) <> min(cost)) t2
on t1.type = t2.type
Another way is:
select
t.type, t.cost
from t
left join t t1 on t.type = t1.type
and (t.cost <> t1.cost or t1.people = 'amy')
where
not t1.cost is null
group by
t.type, t.cost;
[SQL Fiddle Demo]
Or also:
select *
from t
where exists (
select 1
from t t1
where t1.type = t.type
group by t1.type
having count(distinct t1.cost) > 1
-- below code added your new criteria
union all
select 1
from t t2
where t2.people = 'amy'
);
[SQL Fiddle Demo]
I have the following data:
id userid name group
1 1 A x
2 1 A y
3 1 A z
4 2 B x
5 2 B y
6 3 C y
7 4 D x
8 5 E x
9 5 E z
10 6 F x
I want to find those records that meet all this condition:
Select all rows where the a userid belongs to a group other than y but the userid also belongs to group y.
The resulting dataset will be as follows:
id userid name group
1 1 A x
3 1 A z
4 2 B x
If you see, it has resulted in two records for userid a because these are two two records belong to groups other than y but the userid 1 also belongs to group y. Same for userid 2.
I have been breaking my head on how to get this in an SQL statement but not even close to a solution.
Any help is appreciated.
Use a join:
SELECT t1.*
FROM mytable t1
INNER JOIN mytable t2
ON t1.user_id = t2.user_id AND t1.group <> t2.group AND t2.group = 'y'
I think that would be the fastest query (but please feel free to try the other solutions as well).
Add an index on user_id if not already there and maybe play with some other indexes as well (maybe a composite index on group and user_id can be utilized)
Use exists
select *
from MyTable a2
where name_group <> 'y'
and exists (select 1
from MyTable a2
where a2.name_group = 'y'
and a2.userid = a1.userid)
You can get all the users that meet the condition using aggregation and having:
select userid
from t
group by userid
having sum( group = 'y' ) > 0 and
sum( group <> 'y') > 0;
I leave it to your to put this into a query to get all the original rows.
TABLE 1 TABLE 2
id name mob id course mark
1 joe 0000 1 English 77
2 john 0000 2 maths 89
I need to show the name of the person from table 1 who has the MAX(grade) in table 2 using a nested query.
SELECT t1.name
FROM t1
WHERE t1.id = t2.id = (
SELECT id
FROM t2
WHERE mark =
(
SELECT MAX(mark)
FROM t2
)
);
Well, this satisfies the brief ;-):
SELECT a.*
FROM table_a a
JOIN (SELECT * FROM table_b) b
ON b.id = a.id
ORDER
BY mark DESC
LIMIT 1;
I want to count how many times each user has rows within '5' of eachother.
For example, Don - 501 and Don - 504 should be counted, while Don - 501 and Don - 1600 should not be counted.
Start:
Name value
_________ ______________
Don 1235
Don 6012
Don 6014
Don 6300
James 9000
James 9502
James 9600
Sarah 1110
Sarah 1111
Sarah 1112
Sarah 1500
Becca 0500
Becca 0508
Becca 0709
Finish:
Name difference_5
__________ _____________
Don 1
James 0
Sarah 2
Becca 0
Use the ABS() function, in conjunction with a self-join in a subquery:
So, something like:
SELECT name, COUNT(*) / 2 AS difference_5
FROM (
SELECT a.name name, ABS(a.value - b.value)
FROM tbl a JOIN tbl b USING(name)
WHERE ABS(a.value - b.value) BETWEEN 1 AND 5
) AS t GROUP BY name
edited as per Andreas' comment.
Assuming that each name -> value pair is unique, this will get you the count of times the value is within 5 per name:
SELECT a.name,
COUNT(b.name) / 2 AS difference_5
FROM tbl a
LEFT JOIN tbl b ON a.name = b.name AND
a.value <> b.value AND
ABS(a.value - b.value) <= 5
GROUP BY a.name
As you'll notice, we also have to exclude the pairs that are equal to themselves.
But if you wanted to count the number of times each name's values came within 5 of any value in the table, you can use:
SELECT a.name,
COUNT(b.name) / 2 AS difference_5
FROM tbl a
LEFT JOIN tbl b ON NOT (a.name = b.name AND a.value = b.value) AND
ABS(a.value - b.value) <= 5
GROUP BY a.name
See the SQLFiddle Demo for both solutions.
Because the OP also wants de zero counts, we'll need a self- left join. Extra logic is needed if one person has two exactly the same values, these should also be counted only once.
WITH cnts AS (
WITH pair AS (
SELECT t1.zname,t1.zvalue
FROM ztable t1
JOIN ztable t2
ON t1.zname = t2.zname
WHERE ( t1.zvalue < t2.zvalue
AND t1.zvalue >= t2.zvalue - 5 )
OR (t1.zvalue = t2.zvalue AND t1.ctid < t2.ctid)
)
SELECT DISTINCT zname
, COUNT(*) AS znumber
FROM pair
GROUP BY zname
)
, names AS (
SELECT distinct zname AS zname
FROM ztable
GROUP BY zname
)
SELECT n.zname
, COALESCE(c.znumber,0) AS znumber
FROM names n
LEFT JOIN cnts c ON n.zname = c.zname
;
RESULT:
DROP SCHEMA
CREATE SCHEMA
SET
CREATE TABLE
INSERT 0 14
zname | znumber
-------+---------
Sarah | 3
Don | 1
Becca | 0
James | 0
(4 rows)
NOTE: sorry for the CTE, I had not seen th mysql tag,I just liked the problem ;-)
SELECT
A.Name,
SUM(CASE WHEN (A.Value < B.Value) AND (A.Value >= B.Value - 5) THEN 1 ELSE 0 END) Difference_5
FROM
tbl A INNER JOIN
tbl B USING(Name)
GROUP BY
A.Name