join 2 mysql select based on text field - mysql

I have the 2 following select in Mysql:
1st select:
(SELECT DISTINCT `Online_playerdatabase_v2`.`Player`,
Online_playerdatabase_v2.First_Deposit_Date As FirstDep,
TRUNCATE(Online_playerdatabase_v2.Balance,2) as Balance
FROM Online_playerdatabase_v2
WHERE `Online_playerdatabase_v2`.`Player`<>'Player'
ORDER BY `Online_playerdatabase_v2`.`Balance` DESC;
2d select:
SELECT DISTINCT(Online_customer_activity_v2.Customers) as Player,
max(Online_customer_activity_v2.Date) as LastAction
FROM Online_customer_activity_v2
WHERE `Online_customer_activity_v2`.`Total_Bets`>0
Group by Online_customer_activity_v2.Customers
Output Select 1
Player FirstDep Balance
Ray 2014-10-19 9100.00
Ramzi 2014-11-02 9.61
tareq 2014-11-06 805.00
STAN 2014-10-17 7.50
Bill 2014-03-25 68.40
karam 2014-11-16 676.50
Abdul 2014-11-13 650.00
Renaud 2014-03-12 507.00
John 2014-11-22 500.00
Output select 2
Player LastAction
John 2015-11-13
Bill 2014-12-14
Renaud 2015-03-14
Abdul 2015-11-16
Ray 2015-11-22
STAN 2015-10-29
Ramzi 2015-11-10
Tarek 2015-05-10
karam 2014-12-10
Abdul 2015-02-10
Desired Output, a join on both Select that adds following calculations:
active days (FirstDep-LastAction) and Days_last_Visit (CurrentDate - Last Action)
Summarized in following table:
Player FirstDep Balance LastAction Active_days Days_last_Visit
Ray 2014-10-19 9100.00 2015-11-22 399 1
Ramzi 2014-11-02 9.61 2015-11-10 373 13
tareq 2014-11-06 805.00 2015-05-10 185 197
STAN 2014-10-17 7.50 2015-10-29 377 25
Bill 2014-03-25 68.40 2014-12-14 264 344
karam 2014-11-16 676.50 2014-12-10 24 348
Abdul 2014-11-13 650.00 2015-02-10 89 286
Renaud 2014-03-12 507.00 2015-03-14 367 254
John 2014-11-22 500.00 2015-11-13 356 10
Your help is greatly appreciated!
Thanks

The following query should give the result you want. I will add that I joined the two tables from your intermediate queries above using the Player field. This is not a very robust way to join, because the name may not be unique among all players in the table. A better way to join would be to use a unique identifier of some sort.
SELECT t1.Player, t1.FirstDep, t1.Balance, t2.LastAction,
DATEDIFF(t2.LastAction, t1.FirstDep) AS Active_days,
DATEDIFF(NOW(), t2.LastAction) AS Days_last_Visit
FROM
(
SELECT DISTINCT `Online_playerdatabase_v2`.`Player`,
Online_playerdatabase_v2.First_Deposit_Date AS FirstDep,
TRUNCATE(Online_playerdatabase_v2.Balance,2) AS Balance
FROM Online_playerdatabase_v2
WHERE `Online_playerdatabase_v2`.`Player` <> 'Player'
) t1
INNER JOIN
(
SELECT DISTINCT(Online_customer_activity_v2.Customers) AS Player,
MAX(Online_customer_activity_v2.Date) AS LastAction
FROM Online_customer_activity_v2
WHERE `Online_customer_activity_v2`.`Total_Bets` > 0
GROUP BY Online_customer_activity_v2.Customers
) t2
ON t1.`Player` = t2.`Player`

You need to join the 2 selects as subqueries in a 3rd select using the player field. The Active_days and Days_last_Visit fields can be calculated using the DateDiff() function.
SELECT *
,DateDiff(t2.LastAction,t1.FirstDep) AS Active_days
,DateDiff(CURDATE(), t2.LastAction) AS Days_last_Visit
FROM
(SELECT DISTINCT `Online_playerdatabase_v2`.`Player`,
Online_playerdatabase_v2.First_Deposit_Date As FirstDep,
TRUNCATE(Online_playerdatabase_v2.Balance,2) as Balance
FROM Online_playerdatabase_v2
WHERE `Online_playerdatabase_v2`.`Player`<>'Player'
ORDER BY `Online_playerdatabase_v2`.`Balance` DESC) t1
LEFT JOIN
(SELECT DISTINCT(Online_customer_activity_v2.Customers) as Player,
max(Online_customer_activity_v2.Date) as LastAction
FROM Online_customer_activity_v2
WHERE `Online_customer_activity_v2`.`Total_Bets`>0
Group by Online_customer_activity_v2.Customers) t2
ON t1.Player=t2.Player
You have to consider, however, how you join the 2 datasets. I used left join, since the players table will probably hold all players, but you may want to go for inner join or simulate a full outer join depending your requirements and your data.

Related

SQL subquery in SELECT clause

I'm trying to find admin activity within the last 30 days.
The accounts table stores the user data (username, password, etc.)
At the end of each day, if a user had logged in, it will create a new entry in the player_history table with their updated data. This is so we can track progress over time.
accounts table:
id
username
admin
1
Michael
4
2
Steve
3
3
Louise
3
4
Joe
0
5
Amy
1
player_history table:
id
user_id
created_at
playtime
0
1
2021-04-03
10
1
2
2021-04-04
10
2
3
2021-04-05
15
3
4
2021-04-10
20
4
5
2021-04-11
20
5
1
2021-05-12
40
6
2
2021-05-13
55
7
3
2021-05-17
65
8
4
2021-05-19
75
9
5
2021-05-23
30
10
1
2021-06-01
60
11
2
2021-06-02
65
12
3
2021-06-02
67
13
4
2021-06-03
90
The following query
SELECT a.`username`, SEC_TO_TIME((MAX(h.`playtime`) - MIN(h.`playtime`))*60) as 'time' FROM `player_history` h, `accounts` a WHERE h.`created_at` > '2021-05-06' AND h.`user_id` = a.`id` AND a.`admin` > 0 GROUP BY h.`user_id`
Outputs this table:
Note that this is just admin activity, so Joe is not included in this data.
from 2021-05-06 to present (yy-mm-dd):
username
time
Michael
00:20:00
Steve
00:10:00
Louise
00:02:00
Amy
00:00:00
As you can see this from data, Amy's time is shown as 0 although she has played for 10 minutes in the last month. This is because she only has 1 entry starting from 2021-05-06 so there is no data to compare to. It is 0 because 10-10 = 0.
Another flaw is that it doesn't include all activity in the last month, basically only subtracts the highest value from the lowest.
So I tried fixing this by comparing the highest value after 2021-05-06 to their most previous login before the date. So I modified the query a bit:
SELECT a.`Username`, SEC_TO_TIME((MAX(h.`playtime`) - (SELECT MAX(`playtime`) FROM `player_history` WHERE a.`id` = `user_id` AND `created_at` < '2021-05-06'))*60) as 'Time' FROM `player_history` h, `accounts` a WHERE h.`created_at` >= '2021-05-06' AND h.`user_id` = a.`id` AND a.`admin` > 0 GROUP BY h.`user_id`
So now it will output:
username
time
Michael
00:50:00
Steve
00:50:00
Louise
00:52:00
Amy
00:10:00
But I feel like this whole query is quite inefficient. Is there a better way to do this?
I think you want lag():
SELECT a.username,
SEC_TO_TIME(SUM(h.playtime - COALESCE(h.prev_playtime, 0))) as time
FROM accounts a JOIN
(SELECT h.*,
LAG(playtime) OVER (PARTITION BY u.user_id ORDER BY h.created_at) as prev_playtime
FROM player_history h
) h
ON h.user_id = a.id
WHERE h.created_at > '2021-05-06' AND
a.admin > 0
GROUP BY a.username;
In addition to the LAG() logic, note the other changes to the query:
The use of proper, explicit, standard, readable JOIN syntax.
The use of consistent columns for the SELECT and GROUP BY.
The removal of single quotes around the column alias.
The removal of backticks; they just clutter the query, making it harder to write and to read.

rank on mysql with join

i need to display rank with my sql on 2 joined table, there's my mysql query to display
SELECT a.UserID, b.Nama,a.Matematika,a.IPA,a.IPS,a.BIND,a.BING,a.Rata,
FIND_IN_SET( a.Rata, (SELECT GROUP_CONCAT( a.Rata ORDER BY a.Rata DESC ) FROM datanilaiujian )) AS rank
from datanilaiujian as a JOIN
datauser as b
ON a.UserID=b.UserID
ORDER BY a.Rata DESC
but when i execute this command, mysql return Error Code: 1242. Subquery returns more than 1 row
list field on table datanilaiujian
UserID Matematika IPA IPS BIND BING Rata
1000 90 76 78.9 78 65 77.58
1001 78.9 87 67 56 78 73.38
1002 80 78.9 67 55 65.9 69.36
1003 78.9 56 77 88 90 77.97999999999999
list field on table datauser
UserID Pass Nama Alamat NoTelepon AsalSekolah Tanggal Masuk NilaiUN
1000 1000 Habib Jl.sesama 232323232323 23dsdsdsfsdfsdfsdfsdff 2017-01-13 19:35:22 Sudah
1001 1001 wisnu jl sesama 085600336706 SMA 2 Purwokerto 2017-01-28 17:35:32 Sudah
1002 1002 Arif Jl Sungkio 085600336706 SMA BINTEK 2017-01-28 19:30:56 Sudah
1003 1003 Akbar Jl sesama 085600133558 SMPN 1 Purwokerto 2017-02-02 18:59:47 Sudah
my expected result :
Nama Matematika IPA IPS BIND BING Rata Rank
I see the problem. Your subquery is saying a.Rata. This refers to the outer table. I suspect that the GROUP_CONCAT() is then confusing MySQL, so the subquery is not interpreted as an aggregation query.
However, you should move the subquery to the FROM clause:
SELECT a.*,
FIND_IN_SET( a.Rata, l.list) AS rank
from datanilaiujian a JOIN
datauser b
ON a.UserID = b.UserID CROSS JOIN
(SELECT GROUP_CONCAT( a2.Rata ORDER BY a2.Rata DESC ) as list
FROM datanilaiujian a2
) l
ORDER BY a.Rata DESC;
This generally helps the optimizer choose the best execution plan.

Join 2 mysql Tables SUM and COUNT based on text field

thanks in advance for your help on this !
I have 2 tables that I need to join based on 2 different SELECTs
First Select:
SELECT
Agent,
count( Online_playerdatabase_v2.First_Deposit_Date) as NumbFirstDeposits
FROM Online_playerdatabase_v2
WHERE Agent <>'Agent' AND Online_playerdatabase_v2.First_Deposit_Date BETWEEN '2015-12-01' AND '2015-12-31'
group by Agent
Output:
Agent NumbFirstDeposits
john 49
No Agent 1
mike 9
Then another Select:
SELECT
Agent,
COUNT(DISTINCT Online_customer_activity_v2.Customers) as ActivePlayers,
Truncate(sum(Online_customer_activity_v2.Real_Money),0) as RM,
Truncate(sum(Online_customer_activity_v2._Bonuses),0) as BO,
Truncate(sum(Online_customer_activity_v2.Total_Win_Loss),0) as GGR,
Truncate(sum(`Online_customer_activity_v2`.`Total_Bets`),0) as BETS
FROM Online_customer_activity_v2
WHERE `Online_customer_activity_v2`.`Date` BETWEEN '2015-12-01' AND '2015-12-31'
AND Online_customer_activity_v2.Total_Bets>0
GROUP BY Agent
Output:
Agent ActivePlayers RM BO GGR BETS
john 73 63118 28538 64 1395799
No Agent 1 80 0 - 21 876
mike 24 209780 28464 20 7955633
I would like to have a Join of the 2 outputs as below:
Agent ActivePlayers RM BO GGR BETS NumbFirstDeposits
john 73 63118 28538 64 1395799 49
No Agent 1 80 0 - 21 876 1
mike 24 209780 28464 20 7955633 9
One way to do this without having to rewrite the queries is to use them both at derived tables like this:
select t1.*, t2.NumbFirstDeposits
from (<<your first query here>>) t1
join (<<your second query here>> t2 on t1.agent = t2.agent
Try to apply join like this way:
SELECT ***your_column_names_here***
FROM Online_playerdatabase_v2 as P
join Online_customer_activity_v2 as C on P.Agent=C.agent
WHERE
***conditions***
Group BY p.Agent
You can try this,
SELECT Online_customer_activity_v2.Agent,
COUNT(DISTINCT Online_customer_activity_v2.Customers) as ActivePlayers,
Truncate(sum(Online_customer_activity_v2.Real_Money),0) as RM,
Truncate(sum(Online_customer_activity_v2._Bonuses),0) as BO,
Truncate(sum(Online_customer_activity_v2.Total_Win_Loss),0) as GGR,
Truncate(sum(`Online_customer_activity_v2`.`Total_Bets`),0) as BETS,
count( Online_playerdatabase_v2.First_Deposit_Date) as NumbFirstDeposits FROM Online_customer_activity_v2 join Online_playerdatabase_v2 on Online_playerdatabase_v2.agent=Online_customer_activity_v2.agent WHERE `Online_customer_activity_v2`.`Date` BETWEEN '2015-12-01' AND '2015-12-31' AND Online_customer_activity_v2.Total_Bets>0 GROUP BY Online_customer_activity_v2.Agent

how to group_concat using distinct correctly - MYSQL

I have 3 table relation using MYSQL;
Example first as riders table:
bib | series_id | point
202 3 200
219 3 140
202 2 200
219 2 110
10 1 90
Example second as series table:
series_id | series_no | season_id
1 1 2
2 2 1
3 1 1
Example third as seasons table:
season_id | year
1 2015
2 2016
How to GROUP_CONCAT point correctly? I'm trying like this
SELECT riders.bib, seasons.year, GROUP_CONCAT(DISTINCT riders.point ORDER BY series.series_no DESC) AS seriPoint
FROM series, riders, seasons
GROUP BY riders.bib
I'm getting output seriPoint for bib: 202 is 200 and bib: 219 is 140,110 when I'm using DISTINCT output like that. But when I'm not using DISTINCT getting output seriPoint for bib: 202 is 200,200,200,200 and bib: 219 is 140,110,140,110. What I want is output seriPoint for bib: 202 is 200,200 and bib: 219 is 140,110.
ADD: please help to add filter too, for season_id when different season_id its to be different row.
yes you are getting correct output since you have used DISTINCT. BTW, you should change your query to use proper JOINS
SELECT riders.bib,
seasons.year,
GROUP_CONCAT(DISTINCT riders.point ORDER BY series.series_no DESC) AS seriPoint
FROM riders
JOIN series ON series.series_id = riders.series_id
JOIN seasons ON series.season_id = seasons.season_id
GROUP BY riders.bib;
(OR) you can get the grouping first and then perform join like
select seasons.year, xx.bib, xx.seriPoint
FROM series
JOIN (
select series_id, bib
group_concat(point) as seriPoint
from riders
group by bib ) xx ON series.series_id = xx.series_id
JOIN seasons ON series.season_id = seasons.season_id
order by xx.seriPoint;

Join condition retrieving undesired answer

I have 2 tables and is as follows
select Event_ID,[Gross Salary] from tblEar where Event_ID=14
Result:
Event_ID Gross Salary
14 56128
14 51984
14 42028
And:
select EventId, [Order Date],Amount from tblBudget where EventId=14
Result:
EventId Order Date Amount
14 10/10/2011 20000
14 10/10/2011 20000
14 20/03/2012 2500
14 02/04/2012 -50000
if i write a join statment on these 2 tables to get it is retrieving duplicate records.I used Distinct But no Positive Result.
select DISTINCT tba.[Order Date],ISNULL(tba.Amount,0),ISNULL(te.[Gross Salary],0) from tblBudget tba
join
tblEar te on tba.EventId=te.Event_ID where tba.EventId=14
I got the following ans:
Order Date (No column name) (No column name)
2011-10-10 20000.00 42028.00
2011-10-10 20000.00 51984.00
2011-10-10 20000.00 56128.00
2012-03-20 2500.00 42028.00
2012-03-20 2500.00 51984.00
2012-03-20 2500.00 56128.00
2012-04-02 -50000.00 42028.00
2012-04-02 -50000.00 51984.00
2012-04-02 -50000.00 56128.00
Can any one show the Way to get Accuarate data
I guess you want to group the data and aggregate the amounts:
SELECT tba.[Order Date], SUM(tba.Amount), SUM(te.[Gross Salary])
FROM tblBudget tba
JOIN tblEar te on tba.EventId = te.Event_ID
WHERE tba.EventId = 14
GROUP BY tba.[Order Date]