The table has 4 columns Match, Winning_Player_ID, Losing_Player_ID, Quantity_Points_Exchanged_for_that_match. I would like to in a single query show the total number of points each player won and earned over all matches.
Here is the table
M WIN LOSE QTY
1 100 201 10
2 201 100 05
3 100 201 05
4 302 100 05
For output I would like total it in this way in a single query and cannot figure it out.
ID WIN LOSE
100 15 10
201 05 15
302 05 00
SELECT p.player ID,
(SELECT SUM(QTY) FROM tbl WHERE WIN = p.player) WIN,
(SELECT SUM(QTY) FROM tbl WHERE LOSE = p.player) LOSE
FROM
(SELECT DISTINCT WIN player FROM tbl
UNION
SELECT DISTINCT LOSE FROM tbl) p
No db available to check this out, but perhaps something like this:
SELECT player, SUM(winQty) AS WIN, SUM(loseQty) AS LOSE
FROM ( SELECT win AS player, qty AS winQty, 0 AS loseQty
FROM myTable
UNION ALL
SELECT lose AS player, 0 AS winQty, qty AS loseQty
FROM myTable
) x
GROUP BY player
UPDATE: Changed UNION to UNION ALL
Here's the answer:
CREATE THE TABLE:
CREATE TABLE table_name (
m int,
win int,
lose int,
qty int);
INSERT THE DATA:
INSERT INTO table_name (m, win, lose, qty)
values
(1, 100, 201, 10),
(2, 201, 100, 05),
(3, 100, 201, 05),
(4, 302, 100, 05);
The QUERY:
SELECT id, sum(won), sum(lost) from (
SELECT win as id, SUM(qty) as won, 0 as lost
FROM table_name W GROUP BY win
UNION
SELECT lose as id, 0 as won, SUM(qty) as lost
FROM table_name W GROUP BY lose
) sums
GROUP BY ID
The result:
+------+----------+-----------+
| id | sum(won) | sum(lost) |
+------+----------+-----------+
| 100 | 15 | 10 |
| 201 | 5 | 15 |
| 302 | 5 | 0 |
+------+----------+-----------+
Related
Refer to another Stack Overflow question here, however the answers there didn't include the group_id 3 player.
I tried to replicate the answer in MySQL but I am not familiar with PostgreSQL. Anyone can show how to proceed it in MySQL?
The question is to return the max scored player as winner_id from each group
create table players (
player_id integer not null unique,
group_id integer not null
);
create table matches (
match_id integer not null unique,
first_player integer not null,
second_player integer not null,
first_score integer not null,
second_score integer not null
);
insert into players values(20, 2);
insert into players values(30, 1);
insert into players values(40, 3);
insert into players values(45, 1);
insert into players values(50, 2);
insert into players values(65, 1);
insert into matches values(1, 30, 45, 10, 12);
insert into matches values(2, 20, 50, 5, 5);
insert into matches values(13, 65, 45, 10, 10);
insert into matches values(5, 30, 65, 3, 15);
insert into matches values(42, 45, 65, 8, 4);
matches table
match_id | first_player | second_player | first_score | second_score
----------+--------------+---------------+-------------+--------------
1 | 30 | 45 | 10 | 12
2 | 20 | 50 | 5 | 5
13 | 65 | 45 | 10 | 10
5 | 30 | 65 | 3 | 15
42 | 45 | 65 | 8 | 4
Expected output
group_id | winner_id
----------+-----------
1 | 45
2 | 20
3 | 40
I presume that since you can't use the solution to the other question that you are using MySQL 5.7 or below. In that case, you have to simulate the ROW_NUMBER/PARTITION functionality, which you can do with a LEFT JOIN from a derived table of scores per player with itself, joining on the score being greater than that in the first table. Any player who has no scores greater in the joined table clearly has the highest score. Since there can be ties, we then take the minimum of the player_id values from that table (when there is no tie, this has no effect).
SELECT group_id, MIN(player_id) AS player_id
FROM (
SELECT t1.group_id, t1.player_id
FROM (
SELECT p.player_id, p.group_id,
SUM(CASE WHEN m.first_player = p.player_id THEN m.first_score
ELSE m.second_score
END) AS score
FROM players p
LEFT JOIN matches m ON m.first_player = p.player_id OR m.second_player = p.player_id
GROUP BY p.player_id, p.group_id
) t1
LEFT JOIN (
SELECT p.player_id, p.group_id,
SUM(CASE WHEN m.first_player = p.player_id THEN m.first_score
ELSE m.second_score
END) AS score
FROM players p
LEFT JOIN matches m ON m.first_player = p.player_id OR m.second_player = p.player_id
GROUP BY p.player_id, p.group_id
) t2 ON t2.group_id = t1.group_id AND t2.score > t1.score
GROUP BY t1.group_id, t1.player_id
HAVING COUNT(t2.player_id) = 0
) w
GROUP BY group_id
Output:
group_id player_id
1 45
2 20
3 40
Demo on db-fiddle
I have transaction data like this example:
Name | Price
George | 20
George | 20
George | 20
George | 30
Paul | 20
Paul | 20
Paul | 30
Paul | 30
Paul | 35
I need to group by user and sort by the number of transactions in general, but within that group of users also make groups by price ordering by the amount of transactions at that price.
I need this result:
Name | Price | Count
Paul | 20 | 2
Paul | 30 | 2
Paul | 35 | 1
George | 20 | 3
George | 30 | 1
UPDATE
It is in a MySQL 5.5 database. I need to make the query for fluent in Laravel but having it in SQL is a great advance.
Thanks in advance.
SELECT t1.*
FROM ( SELECT name,
price,
COUNT(*) cnt
FROM srctable
GROUP BY name, price ) t1
JOIN ( SELECT name,
COUNT(*) tcnt
FROM srctable
GROUP BY name ) t2 USING (name)
ORDER BY tcnt DESC,
cnt DESC;
fiddle
Here you go. It can be done in MySQL 8.x. The double ordering you want requires the use of a couple of table expressions, as shown below:
select
x.name, x.price, x.cnt
from (
select name, price, count(*) as cnt
from t
group by name, price
) x
join (
select name, row_number() over(order by cnt desc) as ob
from (
select name, count(*) as cnt
from t
group by name
) y
) z on x.name = z.name
order by z.ob, x.cnt desc
Result:
name price cnt
------ ----- ---
Paul 20 2
Paul 30 2
Paul 35 1
George 20 3
George 30 1
For reference, the data script I used is:
create table t (
name varchar(10),
price int
);
insert into t (name, price) values
('George', 20),
('George', 20),
('George', 20),
('George', 30),
('Paul', 20),
('Paul', 20),
('Paul', 30),
('Paul', 30),
('Paul', 35);
I have a table like this
idGoal | idMatch | minute
1 | 1 | 30
2 | 1 | 40
3 | 2 | 30
4 | 3 | 45
I want to get only the goals where the minute are the same on distinct matches.
So it shows idGoal 1 and 3.
I would use exists:
select g.*
from goals g
where exists (select 1
from goals g2
where g2.minute = g.minute and
g2.idMatch <> g.idMatch
);
In particular, exists can take advantage of an index on (minute, idMatch).
Your table:
CREATE TABLE goals
(idGoal INT, idMatch INT, minute TINYINT);
Your data:
INSERT INTO goals
(idGoal, idMatch, minute)
VALUES
(1, 1, 30),
(2, 1, 40),
(3, 2, 30),
(4, 3, 45);
Your query:
SELECT idGoal
FROM goals
WHERE minute IN
(
SELECT minute
FROM goals
GROUP BY minute
HAVING COUNT(*) > 1
);
Your result:
idGoal
------
1
3
I would like to count the date-time difference, when I group the data.
Lets have a look on table content example :
id | session_id | created
1 | 101 | 1/10/2010 9:30:10
2 | 102 | 1/10/2010 9:31:10
3 | 101 | 1/10/2010 9:32:10
4 | 103 | 1/10/2010 9:35:10
5 | 102 | 1/10/2010 9:38:10
6 | 103 | 1/10/2010 9:39:10
Output should be as follow :
session_id | time_count
101 | 2 (minutes)
102 | 7 (minutes)
103 | 4 (minutes)
So here i want to calculate time difference of 'created' field for data which is group by session_id.
Any help would be great. Thanks in advance :)
My Situation :
I have a table with following fields :
id, session_id, platform, event, created
there are 2 event (Start,End)
Now if there are records of Start and End for same session_id then i want the time takes to complete this session.
But if i have 2 Start session, but only 1 End session then i do not want the time difference for 2nd Session because it did not end
SELECT session_id,
DATEDIFF(MINUTE, MAX(created), MIN(created)) AS diff
FROM table
GROUP BY session_id
Try this:
Table Schema:
CREATE TABLE A(id INT, session_id INT,Event VARCHAR(20), created DATETIME);
INSERT INTO A VALUES(1, 101,'Start','2010/10/01 9:30:10')
,(2, 102,'Start' , '2010/10/01 9:31:10')
,(3, 101,'End' , '2010/10/01 9:32:10')
,(4, 103,'Start' , '2010/10/01 9:35:10')
,(5, 102,'End' , '2010/10/01 9:38:10')
,(6, 103,'End' , '2010/10/01 9:39:10')
,(7, 101,'Start' , '2010/10/01 9:39:10')
,(8, 102,'Start' , '2010/10/01 9:39:10')
,(9, 101,'End' , '2010/10/01 9:55:10');
Query:
SELECT D.session_id
,TIMESTAMPDIFF(MINUTE,MIN(D.created), MAX(D.created)) time_count
FROM(
SELECT a.id,a.session_id,a.created
,ROUND(count(*)/2,0) as RN
,count(*) as row_number1
FROM a AS a
JOIN a AS b ON a.session_id = b.session_id AND a.id >= b.id
GROUP BY a.id,a.session_id,a.created
ORDER BY 2,3
)D
GROUP BY D.session_id,D.RN
HAVING COUNT(1)>1
Output:
session_id time_count
101 2
102 7
103 4
101 16
Fiddle:
Check the Output in the #SQL Fiddle
You can try it's sintax :
WITH cte AS (
SELECT
session_id,
DATEDIFF(minute, created, LAG(created, 1)) AS diff,
ROW_NUMBER() OVER (PARTITION BY session_id ORDER BY created) rn
FROM yourTable
)
SELECT
session_id,
diff AS time_count
FROM cte
WHERE rn % 2 = 0
;
I have a booking table where all the service booking list where booking details saved like this:
id user_id booking_date booking_id
1 3 2017-01-10 booking1
2 3 2017-01-11 booking1
3 3 2017-01-12 booking1
4 3 2017-01-13 booking1
5 3 2017-01-14 booking1
6 4 2017-01-19 booking2
7 4 2017-01-20 booking2
8 4 2017-01-21 booking2
9 4 2017-01-22 booking2
10 3 2017-02-14 booking3
11 3 2017-02-15 booking3
I want to get a start and end date of booking that came in a row.
like for user_id 3 has 2 date range of booking date
from `2017-01-10 to 2017-01-14`
and then after some records
from `2017-02-14 to 2017-02-15`
First of all, I don't think that getting sequences like that does make sense. ... But, ok.
To do this in one Query would be compicated with that data. So I would first add some column like "group_id" or "order_id". So you can save one ID to all orders that belong together.
Just iterate over the Table, ascending by ID and check if the next (or last) data has the same user_id.
When you do have the order_id column, you can simple
SELECT MIN(booking_date), MAX(booking_date) FROM table GROUP BY order_id
Ok, nobody says it is easy ... let's go. This is a gap and island problem. let me say it is mooooore easy to solve in postges sql
I apply mysql variables to your scenario.
I solve it on SQL Fiddle:
MySQL 5.6 Schema Setup:
create table t ( user_id int, booking_date date );
insert into t values
( 3, '2017-01-10'),
( 3, '2017-01-11'),
( 3, '2017-01-12'),
( 3, '2017-01-13'),
( 3, '2017-01-14'),
( 4, '2017-01-19'),
( 4, '2017-01-20'),
( 4, '2017-01-21'),
( 4, '2017-01-22'),
( 3, '2017-02-14'),
( 3, '2017-02-15');
Query 1:
select user_id, min(booking_date), max(booking_date)
from (
select t1.user_id,
t1.booking_date,
#g := case when(
DATE_ADD(#previous_date, INTERVAL 1 DAY) <> t1.booking_date or
#previous_user <> t1.user_id )
then t1.booking_date
else #g
end as g,
#previous_user:= t1.user_id,
#previous_date:= t1.booking_date
from t t1, ( select
#previous_user := -1,
#previous_date := STR_TO_DATE('01/01/2000', '%m/%d/%Y'),
#g:=STR_TO_DATE('01/01/2000', '%m/%d/%Y') ) x
order by user_id, booking_date
) X
group by user_id, g
Results:
| user_id | min(booking_date) | max(booking_date) |
|---------|-------------------|-------------------|
| 3 | 2017-01-10 | 2017-01-14 |
| 3 | 2017-02-14 | 2017-02-15 |
| 4 | 2017-01-19 | 2017-01-22 |
Explanation nested query figure up a group code ( g ) for each range. The external query get the max and the min for each group.