If I have three columns:
id, username, time
My data is:
+-------+------------------+-------------+
| id | username | time |
+-------+------------------+-------------+
| 1 | A | 1 min |
| 2 | A | 2 min |
| 3 | B | 3 min |
| 4 | B | 4 min |
+-------+------------------+-------------+
This query is working to get the ranking:
SELECT time,
FIND_IN_SET(MIN(time), (SELECT GROUP_CONCAT(time ORDER BY time ASC)
FROM table t1)) AS rank
FROM table t2
WHERE t2.username = 'B';
There is only one problem: It returns Rank 3de for the user B instead 2nd.
So I tried to use GROUP BY t2.username and also Distinct t2.username but did not work.
How can I get the rank of THE user B? It should be 2 (Not 3) because we have only 2 users.
E.g.:
DROP TABLE IF EXISTS my_table;
CREATE TABLE my_table
(id INT NOT NULL
,username CHAR(1) NOT NULL
,time TIME NOT NULL
);
INSERT INTO my_table VALUES
(1,'A','00:01:00'),
(2,'A','00:02:00'),
(3,'B','00:03:00'),
(4,'B','00:04:00');
SELECT * FROM my_table;
+----+----------+----------+
| id | username | time |
+----+----------+----------+
| 1 | A | 00:01:00 |
| 2 | A | 00:02:00 |
| 3 | B | 00:03:00 |
| 4 | B | 00:04:00 |
+----+----------+----------+
SELECT *
FROM
( SELECT username
, time
, #i:=#i+1 rank
FROM
( SELECT username
, MIN(time) time
FROM my_table
GROUP
BY username
) x
, (SELECT #i:=0) vars
ORDER
BY time
) n
WHERE username = 'B';
+----------+----------+------+
| username | time | rank |
+----------+----------+------+
| B | 00:03:00 | 2 |
+----------+----------+------+
I think this would work too, but it's slightly hacky, so I'm not sure...
SELECT x.*
, FIND_IN_SET(time,(SELECT GROUP_CONCAT(DISTINCT time ORDER BY time) FROM (SELECT MIN(time) time FROM my_table GROUP BY username) j )) rank
FROM my_table x HAVING rank <> 0 AND username = 'B';
Related
I have the following table:
+----+-----------+------+
| id | table2_id | type |
+----+-----------+------+
| 1 | 100 | A |
| 2 | 100 | B |
| 3 | 100 | C |
| 4 | 100 | A |
| 5 | 250 | A |
+----+-----------+------+
I need a select statement that would get all the records before the first occurrence of type C, per table2_id.
So I want records 1, 2, and 5
I'd do this in code with a loop, but I need to do it in MySQL specifically.
If you are running MySQL 8.0, you can do this with window functions:
select *
from (
select t.*,
min(case when type = 'C' then id end) over(partition by table2_id) min_id
from mytable t
) t
where min_id is null or id < min_id
In all versions, you could use not exists:
select t.*
from mytable t
where not exists (
select 1
from mytable t1
where t1.table2_id = t.table2_id and t1.id <= t.id and t1.type = 'C'
)
Is it possible in SQL to select values in a column then rename the duplicate ones? (assuming maximum of one possible duplicate only)
Let's say I have a table..
| id | name | 0or1_id |
| 0 | Eddy | 0 |
| 1 | Allan | 0 |
| 2 | Eddy | 1 |
| 3 | Allan | 1 |
What query can I do to make it like this?
| id | name | 0or1_id |
| 0 | Eddy | 0 |
| 1 | Allan | 0 |
| 2 | Eddy-copy | 1 |
| 3 | Allan-copy | 1 |
Assuming you want to actually change the data, use update:
update t join
(select name, count(*) as cnt, min(id) as minid
from t
group by name
having cnt > 1
) tt
on t.name = tt.name and t.id <> tt.minid
set name = concat(name, '-copy');
If you only want a select, then the logic is quite similar.
This will work in SQL Server..
select id , name ,0or1_id from (
select id , name ,0or1_id ,row_number() over (partition by name order by id ) as rnm
from table)z1
where rnm =1
union
select id , name || '- Copy' as new_name ,0or1_id from (
select id , name ,0or1_id ,row_number() over (partition by name order by id ) as rnm
from table)z2
where rnm > 2
http://sqlfiddle.com/#!9/3ebaf/1
UPDATE mytable t
INNER JOIN mytable t1
ON t.name = t1.name
AND t.id>t1.id
SET t.name = CONCAT(t.name,'-copy');
I have a Mysql table with the following data.
|ID | Date | BillNumber|BillMonth | Amount | Name |AccNum |
| 2 |2015-09-25| 454345 | 092015 | 135.00 |Andrew Good| 735976|
| 3 |2015-09-26| 356282 | 092015 | 142.00 |Peter Pan | 123489|
| 4 |2015-08-11| 312738 | 082015 | 162.00 |Andrew Good| 735976|
| 5 |2015-07-12| 287628 | 072015 | 220.67 |Andrew Good| 735976|
| 6 |2015-06-12| 100756 | 062015 | 556.34 |Andrew Good| 735976|
What I wanted to achieve is to retrieve the data of Andrew Good with AccNum 735976 for the BillMonth of 092015, provided that the user can entry any of his BillNumber(past/current).
If the reason that that row is of interest is because it is the latest of his rows, try:
select *
from tbl t
where name = ( select name
from tbl
where billnumber = 100756 -- can be any of his
)
and date = ( select max(date)
from tbl x
where x.name = t.name
)
(the billnumber can be any of his)
I have a table called real_estate its structure and data is as follows:-
| id | user_id | details | location | worth
| 1 | 1 | Null | Null | 10000000
| 2 | 1 | Null | Null | 20000000
| 3 | 2 | Null | Null | 10000000
My query is the folloeing:
SELECT * , SUM( worth ) as sum
FROM real_estate
WHERE user_id = '1'
The result which I get from this query is
| id | user_id | details | location | worth | sum
| 1 | 1 | Null | Null | 10000000 | 30000000
I want result to be like
| id | user_id | details | location | worth | sum
| 1 | 1 | Null | Null | 10000000 | 30000000
| 2 | 1 | Null | Null | 20000000 | 30000000
Is there any way to get the result the way I want or should I write 2 different queries?
1)To get the sum of worth
2)To get all the rows for that user
You need to use a subquery that calculates the sum for every user, and then JOIN the result of the subquery with your table:
SELECT real_estate.*, s.user_sum
FROM
real_estate INNER JOIN (SELECT user_id, SUM(worth) AS user_sum
FROM real_estate
GROUP BY user_id) s
ON real_estate.user_id = s.user_id
WHERE
user_id = '1'
but if you just need to return records for a single user, you could use this:
SELECT
real_estate.*,
(SELECT SUM(worth) FROM real_estate WHERE user_id='1') AS user_sum
FROM
real_estate
WHERE
user_id='1'
You can do your sum in a subquery like this
SELECT * , (select SUM(worth) from real_estate WHERE user_id = '1' ) as sum
FROM real_estate WHERE user_id = '1'
Group by id
SELECT * , SUM( worth ) as sum FROM real_estate WHERE user_id = '1' group by id
I have a table that holds usernames and results.
When a user insert his results to the DB, I want to execute a query that will return
the top X results ( with their rank in the db) and will also get that user result
and his rank in the DB.
the result should be like this:
1 playername 4500
2 otherplayer 4100
3 anotherone 3900
...
134 current player 140
I have tried a query with union, but then I didnt get the current player rank.
ideas anyone?
The DB is MYSQL.
10x alot and have agreat weekend :)
EDIT
This is what I have tried:
(select substr(first_name,1,10) as first_name, result
FROM top_scores ts
WHERE result_date >= NOW() - INTERVAL 1 DAY
LIMIT 10)
union
(select substr(first_name,1,10) as first_name, result
FROM top_scores ts
where first_name='XXX' and result=3030);
SET X = 0;
SELECT #X:=#X+1 AS rank, username, result
FROM myTable
ORDER BY result DESC
LIMIT 10;
Re your comment:
How about this:
SET X = 0;
SELECT ranked.*
FROM (
SELECT #X:=#X+1 AS rank, username, result
FROM myTable
ORDER BY result DESC
) AS ranked
WHERE ranked.rank <= 10 OR username = 'current';
Based on what I am reading here:
Your table structure is:
+--------+-------------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+--------+-------------+------+-----+---------+-------+
| name | varchar(50) | YES | | NULL | |
| result | int(11) | YES | | NULL | |
+--------+-------------+------+-----+---------+-------+
Table Data looks like:
+---------+--------+
| name | result |
+---------+--------+
| Player1 | 4500 |
| Player2 | 4100 |
| Player3 | 3900 |
| Player4 | 3800 |
| Player5 | 3700 |
| Player6 | 3600 |
| Player7 | 3500 |
| Player8 | 3400 |
+---------+--------+
You want a result set to look like this:
+------+---------+--------+
| rank | name | result |
+------+---------+--------+
| 1 | Player1 | 4500 |
| 2 | Player2 | 4100 |
| 3 | Player3 | 3900 |
| 4 | Player4 | 3800 |
| 5 | Player5 | 3700 |
| 6 | Player6 | 3600 |
| 7 | Player7 | 3500 |
| 8 | Player8 | 3400 |
+------+---------+--------+
SQL:
set #rank = 0;
select
top_scores.*
from
(select ranks.* from (select #rank:=#rank+1 AS rank, name, result from ranks) ranks) top_scores
where
top_scores.rank <= 5
or (top_scores.result = 3400 and name ='Player8');
That will do what you want it to do
assuming your table has the following columns:
playername
score
calculated_rank
your query should look something like:
select calculated_rank,playername, score
from tablename
order by calculated_rank limit 5
I assume you have PRIMARY KEY on this table. If you don't, just create one. My table structure (because you didn't supply your own) is like this:
id INTEGER
result INTEGER
first_name VARCHAR
SQL query should be like that:
SELECT #i := #i+1 AS position, first_name, result FROM top_scores, (SELECT #i := 0) t ORDER BY result DESC LIMIT 10 UNION
SELECT (SELECT COUNT(id) FROM top_scores t2 WHERE t2.result > t1.result AND t2.id > t1.id) AS position, first_name, result FROM top_scores t1 WHERE id = LAST_INSERT_ID();
I added additional condition into subquery ("AND t2.id > t1.id") to prevent multiple people with same result having same position.
EDIT: If you have some login system, it would be better to save userid with result and get current user result using it.