MySQL queries, max & current rank for players - mysql

In the lists of players I need to find find the maximum rating and current rating
Petr | 1 | 2016-12-01 00:00:00
Petr | 2 | 2016-12-02 00:00:00
Petr | 3 | 2016-12-03 00:00:00
Oleg | 3 | 2016-12-01 00:00:00
Oleg | 2 | 2016-12-02 00:00:00
Oleg | 1 | 2016-12-03 00:00:00
I want to get a Output:
name | min | current
Petr | 1 | 3
Oleg | 1 | 1
For to find the maximum, I try
SELECT t1.rank as min
FROM table t1
LEFT JOIN table t2
ON t1.name = t2.name AND t1.rank > t2.rank
WHERE t2.name IS NULL
And other solve, for find the current
SELECT t1.rank as current
FROM table t1
WHERE t1.dt=(SELECT MAX(dt) FROM table t2 WHERE t1.name = t2.name)

I think you are looking for the minimum rating not maximum.
To get current, the rating with max date, use GROUP BY and then join the original table again, to get the rating value for this max date:
SELECT
t1.Name,
MAX(t2.MinRating) AS MinRating,
MAX(t1.Rating) AS Current
FROM yourTable AS t1
INNER JOIN
(
SELECT Name, MIN(rating) AS MinRating, MAX(rateDate) AS MaxRateDate
FROM yourTable
GROUP BY Name
) AS t2 ON t1.Name = t2.Name AND t1.rateDate = t2.MaxRateDate
GROUP BY t1.Name;
fiddle demo
| Name | MinRating | Current |
|------|-----------|---------|
| Oleg | 1 | 1 |
| Petr | 1 | 3 |

Related

How can I select rows with an extra column joined from the same table

I have a table like this:
id | path | name | date | data
---+-----------+------+------------+-----
1 | Docs | 1000 | 2022-01-01 | aaa0
2 | Docs/1000 | Text | 2022-01-11 | AAA0
3 | Docs | 1001 | 2022-02-02 | aaa1
4 | Docs/1001 | Text | 2022-02-12 | AAA1
How can I select all rows with path 'Docs' and add the date of the corresponding 'Text', i.e:
id | path | name | date | date_of_text | data
---+------+------+------------+--------------+-----
1 | Docs | 1000 | 2022-01-01 | 2022-01-11 | AAA0
3 | Docs | 1001 | 2022-02-02 | 2022-02-12 | AAA1
You can achieve the desired result with self join -
SELECT T1.id, T1.path, T1.name, T1.date, T2.date date_of_text, T2.data
FROM table_name T1
LEFT JOIN table_name T2 ON T1.name = SUBSTRING(path, POSITION("/" IN path) + 1, LENGTH(path))
WHERE T1.path = 'Docs'
Lots of ways to do this including
correlated sub query
select t.*,id % 2 ,(select date from t t1 where t1.ID = t.id + 1) datetext
from t
where id % 2 > 0;
self join
select t.*,t.id % 2 , t1.date
from t
join t t1 on t1.ID = t.id + 1
where t.id % 2 > 0;
Aggregation
select min(id) id,min(path) path,min(date) date,upper(data) data ,max(date) datetext
from t
group by t.data;

SELECT distinct with multiple columns MySQL

I want to select distinct records in my database but I can't get it to work at all. I have tried DISTINCT and GROUP BY but still no luck.
Example:
This is my code:
SELECT
t1.room_id as Room_ID,
t1.room_name as Room_Name,
t2.price_date as Price_for_date,
t3.amount as Price ,
COUNT(t3.unit_id) as c
FROM
table1 AS t1
LEFT JOIN table3 AS t3 ON t1.room_id = t3.room_id
LEFT JOIN table2 AS t2 ON t3.price_room_id = t2.price_room_id
WHERE
t2.price_date BETWEEN (20180130) AND (20180530)
GROUP BY
t2.price_date,
t1.room_id
ORDER BY
t1.room_id,
t2.price_date DESC
T1:
id | room_id | room_name
-----------------------
1 | room1 | rm1
2 | room2 | rm2
3 | room3 | rm3
4 | room4 | rm4
5 | room5 | rm5
T2:
id | price_room_id | price_date
-------------------------------
1 | 000001 | 2018-01-30
2 | 000002 | 2018-02-30
3 | 000003 | 2018-03-30
4 | 000004 | 2018-04-30
5 | 000005 | 2018-05-30
T3:
id | room_id | price_room_id | amount
-------------------------------------
1 | room1 | 00001 | 100000
2 | room1 | 00002 | 101000
3 | room2 | 00002 | 110000
4 | room3 | 00003 | 200000
5 | room3 | 00004 | 300000
6 | room4 | 00001 | 100000
7 | room5 | 00005 | 350000
What I wanted is to select the room_id, price_room_id, and amount with its latest records between the given dates. From the table above I should get the following:
room_id | price_room_id | amount
-------------------------------------
room1 | 00002 | 101000
room2 | 00002 | 110000
room3 | 00004 | 200000
room4 | 00001 | 100000
room5 | 00005 | 350000
But what I'm getting is like this:
room_id | price_room_id | amount
-------------------------------------
room1 | 00002 | 101000
room1 | 00001 | 100000
room2 | 00002 | 110000
room3 | 00004 | 200000
room3 | 00003 | 110000
room4 | 00001 | 100000
room5 | 00005 | 350000
Try removing the Group by and put DISTINCT in SELECT. SELECT DISTINCT... because group by will group every room_id but in your case you just want to get the latest price_date.
SELECT DISTINCT (t1.room_id as Room_ID),
t1.room_name as Room_Name,
t2.price_room_id as Price_room_id,
t2.price_date as Price_for_date,
t3.amount as Price ,
COUNT(t3.unit_id) as c
FROM
table1 AS t1
LEFT JOIN table3 AS t3 ON t1.room_id = t3.room_id
LEFT JOIN table2 AS t2 ON t3.price_room_id = t2.price_room_id
WHERE
t2.price_date = max(t2.price_date)
ORDER BY
t1.room_id;
Unfortunately I don't have the reputation to comment but what #Caius Jard is saying is that each room_id has multiple price_room_ids which is reflected in the output you actually received. But the result that you want only has one price associated with each room_id so which price_room_id do you want to return for each room_id? From your comment, it seems like you want only the most recent price for each room? However, the initial query that you gave us also has some outputs that are not reflected with the example/desired output you gave. For example, COUNT(t3.unit_id) as c what do you want this output to be?
If you just want to show the latest price_date and COUNT(t3.unit_id) as c with only those latest prices you should probably filter by the latest price_date:
SELECT
t1.room_id as Room_ID,
t1.room_name as Room_Name,
t2.price_room_id as Price_room_id,
t2.price_date as Price_for_date,
t3.amount as Price ,
COUNT(t3.unit_id) as c
FROM
table1 AS t1
LEFT JOIN table3 AS t3 ON t1.room_id = t3.room_id
LEFT JOIN table2 AS t2 ON t3.price_room_id = t2.price_room_id
WHERE
t2.price_date = max(t2.price_date)
GROUP BY
t1.room_id
ORDER BY
t1.room_id;
EDIT:
Okay I think I understand now. I am not really sure how to get the max date from a date interval and I think this probably a super slow query but try this out:
SELECT
t1.room_id as Room_ID,
t1.room_name as Room_Name,
t2.price_room_id as Price_room_id,
t2.price_date as Price_for_date,
t3.amount as Price ,
COUNT(t3.unit_id) as c
FROM
table1 AS t1
LEFT JOIN table3 AS t3 ON t1.room_id = t3.room_id
LEFT JOIN table2 AS t2 ON t3.price_room_id = t2.price_room_id
WHERE
t2.price_date = (select max(t2.price_date) where t2.price_date BETWEEN '2018-01-30' AND '2018-05-30')
GROUP BY
t1.room_id
ORDER BY
t1.room_id;

All Entries on Table 1 but only matching entires on table 2 where table 2 contains where statement

I have a problem joining the following tables in that Table 1 conatins all specialists ie
John (id1)
Pete (id2)
Harry (id3)
Joanne (id4)
etc
Table 2 is only populated when a specialist has availability on a certain day ie
id1 2018-10-19
id3 2018-10-19
The results I need from the MySQL query when I use the where statement table2.date=2018-10-19 is
John 2018-10-19
Pete
Harry 2018-10-19
Joanne
but what I actually get is
John 2018-10-19
Harry 2018-10-19
which is correct but I need all specialists to show in order.
Can any one help with any suggestions please
Unless your question is not a good one (and I suspect that it may be a bad one) you don't need the where statement. So
drop table if exists t1,t2;
create table t1 (id int,val varchar(10));
insert into t1 values
(1,'John' ),
(2,'Pete' ),
(3,'Harry'),
(4,'Joanne');
create table t2(t1id int,dt date);
insert into t2 values
(1 ,'2018-10-19'),
(3 ,'2018-10-19');
SELECT * from t1
LEFT OUTER JOIN t2 ON t1.id = t2.t1id
order by t1.val;
Result
+------+--------+------+------------+
| id | val | t1id | dt |
+------+--------+------+------------+
| 3 | Harry | 3 | 2018-10-19 |
| 4 | Joanne | NULL | NULL |
| 1 | John | 1 | 2018-10-19 |
| 2 | Pete | NULL | NULL |
+------+--------+------+------------+
4 rows in set (0.00 sec)
I have no idea how you would get johns,pete,harry,joanne in your result set if you wish to order by name value.
And '"&request.querystring("d")&"' is not mysql what is this php maybe?
If you are interested in the availability or otherwise for a specific date you would first cross join(creating a cartesian product) specialists to date(s) for example
select t1.id,t1.val,dt
from t1
cross join (select '2018-10-19' dt
#union all select '2018-10-20'
) s;
+------+--------+------------+
| id | val | dt |
+------+--------+------------+
| 1 | John | 2018-10-19 |
| 2 | Pete | 2018-10-19 |
| 3 | Harry | 2018-10-19 |
| 4 | Joanne | 2018-10-19 |
+------+--------+------------+
4 rows in set (0.00 sec)
and then see if they exist in table2
select t.id,t.val,t.dt tdt , ifnull(t2.dt,'Not Available') t2dt
from
(select t1.id,t1.val,dt
from t1
cross join (select '2018-10-19' dt
#union all select '2018-10-20'
) s
) t
left join t2
on t.id = t2.t1id and t2.dt = t.dt
order by t.dt,val;
+------+--------+------------+---------------+
| id | val | tdt | t2dt |
+------+--------+------------+---------------+
| 3 | Harry | 2018-10-19 | 2018-10-19 |
| 4 | Joanne | 2018-10-19 | Not Available |
| 1 | John | 2018-10-19 | 2018-10-19 |
| 2 | Pete | 2018-10-19 | Not Available |
+------+--------+------------+---------------+
Note you can have any number of dates in the cross join by using union. I have 2018-10-20 commented out.
If you have a large range of dates union may become unwieldy and creating a calendar/dates table in your db may be useful and you would substitute that in the cross join. for example
select t.id,t.val,t.dt tdt , ifnull(t2.dt,'Not Available') t2dt
from
(select t1.id,t1.val,dt
from t1
cross join (select dte dt from dates where dte between '2018-10-19' and '2018-10-19'
) s
) t
left join t2
on t.id = t2.t1id and t2.dt = t.dt
order by t.dt,val;
You can of course amend the cross join where condition to whatever you want.

How to find and take difference in column values in SQL

I am faced with a complicated problem of taking difference in values in rows.
Sales column shows in total sales and it is automatically updated. I would like create a table with column SalesUpdate where it takes the difference in Sales from the two most recent Sales value in TABLE 1.
TABLE 1.
№ | Date | Product | Sales
----------------------------------------
1 | 2017-03-01 | Coke | 10
2 | 2017-03-02 | Pepsi | 9
3 | 2017-03-03 | Tea | 12
4 | 2017-03-04 | Coke | 20
5 | 2017-03-05 | Coke | 22
6 | 2017-03-06 | Pepsi | 15
TABLE 2.
№ | Product | Date | SalesUpdate
---------------------------------------------------------------
1 | Coke | 2017-03-01 | 22-20 = 2
2 | Pepsi | 2017-03-02 | 15-9 = 6
3 | Tea | 2017-03-03 | 12-0 = 12
Not quite elegant solution, but, at least, not DBMS-specific :) Also, didn't get, what data you want to receive in Date column of resulting set.
SELECT md.product,
md.max_Date Date,
(t1.sales - CASE WHEN t2.sales IS NULL THEN 0 ELSE t2.sales END) SalesUpdate
FROM (SELECT MAX(DATE) max_date,
product
FROM TABLE1
GROUP BY PRODUCT) md
INNER JOIN TABLE1 t1 ON md.product = t1.product AND md.max_date = t1.DATE
LEFT JOIN TABLE1 t2 ON t2.product = t1.product AND t2.date < t1.date
LEFT JOIN TABLE1 t3 ON t2.product = t3.product AND t3.date > t2.date AND t3.date < t1.date
WHERE t3.product IS NULL

mySQL largest value by unique entry

I have tried to solve the following problem for the last couple of hours and could not find anything that pointed me in the right direction on Google or Stackoverflow. I believe that this could be a similar problem, but I did not really understand what the author wanted to achieve, hence I am trying it with my own concrete example:
I have a table that basically tracks prices of different products over time:
+------------+--------+----------+
| Product_id | Price | Time |
+------------+--------+----------+
| 1 | 1.30 | 13:00:00 |
| 1 | 1.10 | 13:30:00 |
| 1 | 1.50 | 14:00:00 |
| 1 | 1.60 | 14:30:00 |
| 2 | 2.10 | 13:00:00 |
| 2 | 2.50 | 13:30:00 |
| 2 | 1.90 | 14:00:00 |
| 2 | 2.00 | 14:30:00 |
| 3 | 1.45 | 13:00:00 |
| 3 | 1.15 | 13:30:00 |
| 3 | 1.50 | 14:00:00 |
| 3 | 1.55 | 14:30:00 |
+------------+--------+----------+
I would now like to query the table so that the rows with max. Price for each product are returned:
+------------+--------+----------+
| Product_id | Price | Time |
+------------+--------+----------+
| 1 | 1.60 | 14:30:00 |
| 2 | 2.50 | 13:30:00 |
| 3 | 1.55 | 14:30:00 |
+------------+--------+----------+
Also, in case of duplicates, i.e. if there is a max. Price at two different points in time, it should only return one row, preferably the one with the smallest value of time.
I have tried MAX() and GREATEST(), but could not achieve the desired outcome to show the wanted values for each product. Efficiency of the query is not the most important factor, but I have about 500 different products with several million rows of data, hence splitting the table by unique product did not seem like an appropriate solution.
Group the data product id and pick the max price and max time
select t1.product_id,t1.price,min(t1.time) as time from your_table t1
inner join (
select Product_id,max(price)as price from
your_table group by Product_id
) t2 on t1.Product_id=t2.Product_id and t1.price=t2.price group by t1.product_id
Sql Fiddle Example:
http://sqlfiddle.com/#!9/020c3/9
http://sqlfiddle.com/#!9/020c3/1
SELECT p.*
FROM prices p
LEFT JOIN prices p1
ON p.product_id = p1.product_id
AND p.time<p1.time
WHERE p1.product_id IS NULL
If you need maximum price to get you can:
http://sqlfiddle.com/#!9/020c3/6
SELECT p.*
FROM prices p
LEFt JOIN prices p1
ON p.product_id = p1.product_id
AND p.price<p1.price
WHERE p1.product_id IS NULL;
And the last approach since I didn't get the goal from the beggining:
http://sqlfiddle.com/#!9/ace04/2
SELECT p.*
FROM prices p
LEFt JOIN prices p1
ON p.product_id = p1.product_id
AND (
p.price<p1.price
OR (p.price=p1.price AND p.time<p1.time)
)
WHERE p1.product_id IS NULL;
This solution is assuming the existence of an additional my_table.id column that needs to be used in case there are duplicate values for (Product_id, price, time) in your table. id is assumed to be a unique value in the table.
SELECT *
FROM my_table t1
WHERE NOT EXISTS (
SELECT *
FROM my_table t2
WHERE t1.Product_id = t2.Product_id
AND ((t1.price < t2.price) OR
(t1.price = t2.price AND t1.time > t2.time) OR
(t1.price = t2.price AND t1.time = t2.time AND t1.id > t2.id))
)
Alternatively, the predicate on price and time could also be expressed using a row value expression predicate (not sure if it's more readable, as t1 and t2 columns are mixed in a each row value expression):
SELECT *
FROM my_table t1
WHERE NOT EXISTS (
SELECT *
FROM my_table t2
WHERE t1.Product_id = t2.Product_id
AND (t1.price, t2.time, t2.id) < (t2.price, t1.time, t1.id)
)