Mysql query Full Join - mysql

I have three tables in my mysql db
dc_match_entries with player_id, goals, yellow cards, own goals etc for each match
dc_player player_id, team_id etc etc
dc_team team_is, some stuff etc etc
And i have this query too
SELECT
dc_player. *,
dc_team.name AS team_name,
dc_team.abbr_name AS team_abbr_name,
COUNT( dc_match_entry.player_id ) AS played,
AVG( dc_match_entry.vote ) AS vote_average,
SUM( dc_match_entry.goal ) AS goal_sum,
SUM( dc_match_entry.own_goal) AS own_goal_sum,
SUM( dc_match_entry.vote ) *10
+ SUM( dc_match_entry.goal ) *10
+ SUM( dc_match_entry.r_card ) *-10
+ SUM( dc_match_entry.y_card ) *-5
+ SUM( dc_match_entry.own_goal ) *-10 AS score,
SUM( dc_match_entry.y_card ) AS y_card_sum,
SUM( dc_match_entry.r_card ) AS r_card_sum
FROM
dc_player,
dc_match_entry,
dc_team
WHERE
dc_player.id = dc_match_entry.player_id AND
dc_player.team = dc_team.id
GROUP BY
dc_player.id
Sadly this query doesn't show players which havent played any match in the competition (since they have no dc_match_entry entries). I can't find a simple (and possibly clear) way to show those players too (full join?)
PS:
this query is nested into a bigger one :
SELECT
L.id,
L.role,
L.first_name,
L.last_name,
L.birth_date,
L.team_name,
L.team_abbr_name,
L.team AS team_id,
L.photo,
L.email,
L.played,
L.vote_average,
L.goal_sum AS goal,
L.own_goal_sum AS own_goal,
L.score +
IFNULL(L.c_mvp, 0)*15
+ IFNULL(unbeaten, 0)*50*IF(L.role='P', 1, 0) AS score,
L.y_card_sum AS y_card,
L.r_card_sum AS r_card,
IFNULL(L.c_mvp, 0) AS mvp,
IFNULL(unbeaten, 0) AS unbeaten
FROM (
SELECT * FROM (
SELECT
dc_player. *,
dc_team.name AS team_name,
dc_team.abbr_name AS team_abbr_name,
COUNT( dc_match_entry.player_id ) AS played,
AVG( dc_match_entry.vote ) AS vote_average,
SUM( dc_match_entry.goal ) AS goal_sum,
SUM( dc_match_entry.own_goal) AS own_goal_sum,
SUM( dc_match_entry.vote ) *10
+ SUM( dc_match_entry.goal ) *10
+ SUM( dc_match_entry.r_card ) *-10
+ SUM( dc_match_entry.y_card ) *-5
+ SUM( dc_match_entry.own_goal ) *-10 AS score,
SUM( dc_match_entry.y_card ) AS y_card_sum,
SUM( dc_match_entry.r_card ) AS r_card_sum
FROM
dc_player,
dc_match_entry,
dc_team
WHERE
dc_player.id = dc_match_entry.player_id AND
dc_player.team = dc_team.id
GROUP BY
dc_player.id
) LOL
LEFT JOIN (
SELECT
COUNT(dc_match.mvp) c_mvp,
mvp AS player_id
FROM dc_match
WHERE
dc_match.mvp IS NOT NULL
GROUP BY dc_match.mvp
) ROFL
ON ROFL.player_id = LOL.id
ORDER BY
LOL.score DESC
) L
LEFT OUTER JOIN(
SELECT
dc_player.id,
COUNT(dc_match.id) AS unbeaten
FROM
dc_match,
dc_match_entry,
dc_player
WHERE
(
(dc_player.team=dc_match.host AND
dc_match.guest_score=0
) OR
(
dc_player.team=dc_match.guest AND
dc_match.host_score=0
)
) AND
dc_player.id = dc_match_entry.player_id AND dc_match.id = dc_match_entry.match_id
GROUP BY
dc_player.id
) I
ON
L.id = I.id
WHERE
L.team = 2
GROUP BY
id
ORDER BY
role DESC, score DESC

You need to use a LEFT JOIN like this:
SELECT ...
FROM dc_player
JOIN dc_team ON (dc_player.team = dc_team.id)
LEFT JOIN dc_match_entry ON (dc_player.id = dc_match_entry.player_id)
GROUP BY dc_player.id
This will return a row for each player whether or not they have any match entries.

Related

Count Total from Multiple Tables

I have list table that basically contains same field on each part.
- p_ticket1_m_site_data | - p_ticket1_ticket | - p_ticket1_last_row
- p_ticket2_m_site_data | - p_ticket2_ticket | - p_ticket2_last_row
- p_ticket3_m_site_data | - p_ticket3_ticket | - p_ticket3_last_row
I can do a count on each table individually:
SELECT COUNT( * ) AS tot_sites, IFNULL( COUNT(
CASE WHEN p_ticket1_m_site_data.m_date_target = DATE( NOW( ) )
THEN 1
ELSE NULL
END ),0) AS todays_target, IFNULL( COUNT(
CASE WHEN (
p_ticket1_m_site_data.m_date_target = DATE( NOW( ) )
AND p_ticket1_ticket.t_status =9 )
THEN 1
ELSE NULL
END ),0
) AS todays_achieve, IFNULL( COUNT(
CASE WHEN p_ticket1_ticket.t_status =9
THEN 1
ELSE NULL
END ),0 ) AS tot_in
FROM p_ticket1_m_site_data
LEFT JOIN p_ticket1_last_row ON p_ticket1_last_row.t_m_id = p_ticket1_m_site_data.m_id
AND p_ticket1_last_row.t_req_type = '04_int_finish_ack'
LEFT JOIN p_ticket1_ticket ON p_ticket1_ticket.t_id = p_ticket1_last_row.t_id
WHERE p_ticket1_m_site_data.m_status =1
What should i do if i want to count all total sites from ticket1, ticket2, ticket3 ?
Please help me guys, thanks . . .
Example use UNION ALL:
I just using UNION ALL in my code above for ticket1 and ticket2, but its not what i want.
My expectation output is count all the ticket tables, so the view is tot_sites (from all ticket), todays_target(from all ticket), todays_achieve(from all ticket), and tot_in(from all ticket)
If you are sure that your tables have the same columns, you should use UNION ALL with CTE
WITH CTE AS (
SELECT *
FROM p_ticket1_m_site_data
UNION ALL
SELECT *
FROM p_ticket2_m_site_data
UNION ALL
...
)
SELECT COUNT(*), ...
FROM CTE
WHERE CTE.m_status = 1
CTE
UNION ALL
You can union the three sets of tables in a sub query and then do your counts in the main query , something like this in principal
SELECT COUNT( * ) AS tot_sites, IFNULL( COUNT(
CASE WHEN m_date_target = DATE( NOW( ) )
THEN 1
ELSE NULL
END ),0) AS todays_target, IFNULL( COUNT(
CASE WHEN (m_date_target = DATE( NOW( ) )
AND t_status =9 )
THEN 1
ELSE NULL
END ),0
) AS todays_achieve, IFNULL( COUNT(
CASE WHEN t_status =9
THEN 1
ELSE NULL
END ),0 ) AS tot_in
from
(
select *
FROM p_ticket1_m_site_data
LEFT JOIN p_ticket1_last_row ON p_ticket1_last_row.t_m_id = p_ticket1_m_site_data.m_id
AND p_ticket1_last_row.t_req_type = '04_int_finish_ack'
LEFT JOIN p_ticket1_ticket ON p_ticket1_ticket.t_id = p_ticket1_last_row.t_id
WHERE p_ticket1_m_site_data.m_status =1
union all
select *
frOM p_ticket2_m_site_data
LEFT JOIN p_ticket2_last_row ON p_ticket2_last_row.t_m_id = p_ticket2_m_site_data.m_id
AND p_ticket2_last_row.t_req_type = '04_int_finish_ack'
LEFT JOIN p_ticket2_ticket ON p_ticket2_ticket.t_id = p_ticket2_last_row.t_id
WHERE p_ticket2_m_site_data.m_status =1
union all
select *
fROM p_ticket3_m_site_data
LEFT JOIN p_ticket3_last_row ON p_ticket3_last_row.t_m_id = p_ticket3_m_site_data.m_id
AND p_ticket3_last_row.t_req_type = '04_int_finish_ack'
LEFT JOIN p_ticket3_ticket ON p_ticket3_ticket.t_id = p_ticket3_last_row.t_id
WHERE p_ticket3_m_site_data.m_status =1
) j;
Which could be tidied up. If this doesn't work for you please add sample data and expected output for your 3 tables as text to the question and I will review.

SQL query adding where related to sub query

Trying to get a where statement on a sub query result. The below works as I want it to, with the exception of AND low_36 != NULL. I need this to stop results where the output of low_36 is NULL.
SELECT offers.*,
(SELECT ROUND( MIN( price ) ,2) FROM o_prices WHERE o_id = offers.id AND months = 23 ) AS low_24,
(SELECT ROUND( MIN( price ) ,2) FROM o_prices WHERE o_id = offers.id AND months = 35 ) AS low_36
(SELECT ROUND( MIN( price ) ,2) FROM o_prices WHERE o_id = offers.id AND months = 47 ) AS low_48
FROM offers
LEFT JOIN m_v ON v_v.code = offers.code
LEFT JOIN m_f_t ON v.f_t_id = m_f_t.id
LEFT JOIN m_t_t ON v.t_t_id = m_t_t.id
WHERE status = 1
AND low_36 != NULL
LIMIT 2 OFFSET 0
I know you can not use results from subqueries in the main where statement, but this is the closest I have come to the correct result. Thank you for any feedback
Quick way would be
SELECT *
FROM
(SELECT offers.*,
(SELECT ROUND( MIN( price ) ,2) FROM o_prices WHERE o_id = offers.id AND months = 23 ) AS low_24,
(SELECT ROUND( MIN( price ) ,2) FROM o_prices WHERE o_id = offers.id AND months = 35 ) AS low_36
(SELECT ROUND( MIN( price ) ,2) FROM o_prices WHERE o_id = offers.id AND months = 47 ) AS low_48
FROM offers
LEFT JOIN m_v ON v_v.code = offers.code
LEFT JOIN m_f_t ON v.f_t_id = m_f_t.id
LEFT JOIN m_t_t ON v.t_t_id = m_t_t.id
WHERE status = 1) a
WHERE low_36 IS NOT NULL
LIMIT 2 OFFSET 0
I suspect you want to exclude null values in the subquery itself, thereby avoiding nullifying your aggregate value. Try this:
SELECT offers.*,
(SELECT ROUND( MIN( price ) ,2) FROM o_prices WHERE o_id = offers.id AND months = 23 ) AS low_24,
(SELECT ROUND( MIN( price ) ,2) FROM o_prices WHERE o_id = offers.id AND months = 35 and price is not null) AS low_36,
(SELECT ROUND( MIN( price ) ,2) FROM o_prices WHERE o_id = offers.id AND months = 47 ) AS low_48
FROM offers
LEFT JOIN m_v ON m_v.code = offers.code
LEFT JOIN m_f_t ON m_v.f_t_id = m_f_t.id
LEFT JOIN m_t_t ON m_f_t.t_t_id = m_t_t.id
WHERE status = 1
LIMIT 2 OFFSET 0

Operand should contain 1 column(s) - in mysql query

I have the following complex query that is giving me an error
Operand should contain 1 column(s)
Can anyone suggest what is wrong
SELECT
t.user_id AS user_id,
t.organisation_id AS organisation_id,
t.firstname AS firstname,
t.surname AS surname,
t.username AS username,
t.year_id AS year_id,
t.form_name AS form_name,
t.House AS House,
rcPoints.total AS milestoneRedeemedCodesTotal,
rcFilteredPoints.total AS redeemedCodesTotalFiltered,
(
COALESCE (rcFilteredPoints.total, 0) - COALESCE (milestoneHistory.total, 0)
) AS redeemedCodesTotalAvailableFiltered,
ABS(
FLOOR(
(
COALESCE (rcFilteredPoints.total, 0) - COALESCE (milestoneHistory.total, 0)
) / 1000
) * 1000
) AS redeemedCodesTotalTowardsMilestone,
ABS(
FLOOR(
(
COALESCE (rcFilteredPoints.total, 0) - COALESCE (milestoneHistory.total, 0)
) / 1000
)
) AS redeemedCodesMilestoneTriggers,
COALESCE (milestoneHistory.total, 0) AS historyTotal
FROM
`myuser` `t`
LEFT JOIN (
SELECT
rc.user_id AS user_id,
SUM(rc.school_points) AS total
FROM
`redeemed_codes` `rc`
INNER JOIN myuser m ON (m.user_id = rc.user_id)
WHERE
(rc.date_redeemed >= 0)
AND (m.organisation_id = 58022)
GROUP BY
rc.user_id
) AS rcPoints ON (rcPoints.user_id = t.user_id)
LEFT JOIN (
SELECT
rc.user_id AS user_id,
SUM(rc.school_points) AS total
FROM
`redeemed_codes` `rc`
INNER JOIN myuser m ON (m.user_id = rc.user_id)
WHERE
(rc.date_redeemed >= 0)
AND (m.organisation_id = 58022)
GROUP BY
rc.user_id
) AS rcFilteredPoints ON (
rcFilteredPoints.user_id = t.user_id
)
LEFT JOIN (
SELECT
mh.user_id AS user_id,
mh.milestone_id AS milestone_id,
MAX(mh.points_when_triggered) AS total
FROM
`milestone_history` `mh`
WHERE
mh.milestone_id = 13
GROUP BY
mh.user_id
) AS milestoneHistory ON (
milestoneHistory.user_id = t.user_id
)
WHERE
(
(
SELECT
COALESCE (count(*), 0)
FROM
milestone_history mha
WHERE
mha.milestone_id = 13
AND mha.user_id = t.user_id
) = 0
)
AND (t.organisation_id = 58022)
AND
(
SELECT * FROM
redeemed_codes t1
WHERE
organisation_id = 1
AND
(
SELECT
sum(school_points)
FROM
redeemed_codes t2
WHERE
t2.redeemed_code_id <= t1.redeemed_code_id
) >= 1000
ORDER BY redeemed_code_id
LIMIT 1
)
GROUP BY
t.user_id
ORDER BY
redeemedCodesMilestoneTriggers DESC
LIMIT 1
Your query might have multiple errors, but this condition in the WHERE clause is definitely suspect and would lead to that error:
AND (SELECT *
FROM redeemed_codes t1
WHERE organisation_id = 1 AND
(SELECT sum(school_points)
FROM redeemed_codes t2
WHERE t2.redeemed_code_id <= t1.redeemed_code_id
) >= 1000
ORDER BY redeemed_code_id
LIMIT 1
)
I have no idea what you are trying to do. Sometimes, the solution is simply EXISTS:
EXISTS (SELECT *
FROM redeemed_codes t1
WHERE organisation_id = 1 AND
(SELECT sum(school_points)
FROM redeemed_codes t2
WHERE t2.redeemed_code_id <= t1.redeemed_code_id
) >= 1000
)

(Newbie) MySQL View

I'm new to SQL and probably going about this the wrong way but could you help?
I need to create a VIEW in MySQL but I can't figure out how to combine these two SQL statements, as VIEWs do not accept multiple SELECTS or Variables.
NB: the second statement works perfectly when replacing the #numberOfGames var with the correct number (manually calculated).
First statement - to return the total number of games for year:
SELECT COUNT( id ) INTO #numberOfGames FROM tblgames WHERE gdate LIKE '2014%';
Second statement - to create VIEW data:
SELECT
p.player AS player,
COUNT( c.gid ) AS gameCount,
SUM( c.cash ) AS cash,
ROUND( AVG( c.cash ), 2 ) AS avg,
SUM( ( CASE WHEN ( c.wotn > 0 ) THEN c.wotn ELSE 0 END ) ) AS wotn,
SUM( ( CASE WHEN ( c.cash > 0 ) THEN c.cash ELSE 0 END ) ) AS cashWon,
SUM( ( CASE WHEN ( c.cash < 0 ) THEN c.cash ELSE 0 END ) ) AS cashLost,
ROUND( AVG( ( CASE WHEN ( c.cash >= 0 ) THEN c.cash END ) ),2 ) AS avgWin,
ROUND( AVG( ( CASE WHEN ( c.cash < 0 ) THEN c.cash END ) ),2 ) AS avgLoss,
IF(
( ( COUNT( c.pid ) > ( #numberOfGames / 3 ) ) AND ( COUNT( c.pid ) > 2 ) ),
ROUND( ( ( AVG( c.cash ) * 10 ) + 200 ), 2 ),
ROUND( AVG( c.cash ), 2 )
) AS sortingPoints
FROM tblplayers p
LEFT JOIN tblcash c ON p.id = c.pid
LEFT JOIN tblgames g ON g.id = c.gid
WHERE c.cash IS NOT NULL AND g.gdate LIKE '2014%'
GROUP BY c.pid
ORDER BY sortingPoints DESC;
I'm using the #numberOfGames vars for a simple maths equation that checks it a player has played more than a third of the total games in the year.
I hope someone can help point me it the right direction.
You are missing the point of what a view does.
You can't save multiple statements in one view. It's like trying to save two tables in one table. It's not possible.
What you need to do is, run your first Select, exactly as you have it. Save it as a view. Then you can use that result set as if it were any other live table, and join it to other tables in subsequent Select statements.

MySQL ORDER BY Aggregate column returning incorrect results

Im struggling to get this query to be able to order by stakes correctly - it returns values that are neither desc or asc. It does work with wins if I use order by. Perhaps MySQL did not evaluate the sort order at the time it was building the aggregation?
I've stripped out some of the full names to make it less tedious to read.
SELECT a.b AS t , COUNT( c.aID ) AS r ,
COUNT(
CASE WHEN c.Finish =1
THEN 1
ELSE NULL
END ) AS wins ,
CONCAT( FORMAT( (
COUNT(
CASE WHEN c.Finish =1
THEN 1
ELSE NULL
END ) / COUNT( c.aID ) ) *100, 0 ) , '%'
) AS Percent ,
FORMAT( SUM( c.StakeWon ) , 0 ) AS stakes
FROM c
INNER JOIN a ON c.aID = a.aID
INNER JOIN d ON c.dID = d.dID
WHERE d.w >= STR_TO_DATE( '2012,07,01', '%Y,%m,%d' )
AND d.w < STR_TO_DATE( '2012,07,01', '%Y,%m,%d' ) + INTERVAL 1
MONTH
GROUP BY a.b
ORDER BY stakes DESC`
It also doesnt work if I order by Percent. I didnt want to ask this question here but this is driving me crazy.
It would help if you show some of the result, but you must sort the stakes before you format it. Then you really sort the numeric value rather than the formatted string.
Here is an example SQL Fiddle how it would go wrong.
The numeric values are not sorted descending because of the formatting
100
10,000,000
-5,000,005
So you would do something like
...
FORMAT( SUM( c.StakeWon ) , 0 ) AS stakes ,
SUM( c.StakeWon ) AS stakes_num
...
ORDER BY stakes_num desc
Example how it would work: SQL Fiddle
Try using this whole expression
COUNT( c.aID ) AS r ,
COUNT(
CASE WHEN c.Finish =1
THEN 1
ELSE NULL
END ) AS wins ,
CONCAT( FORMAT( (
COUNT(
CASE WHEN c.Finish =1
THEN 1
ELSE NULL
END ) / COUNT( c.aID ) ) *100, 0 ) , '%'
) AS Percent ,
FORMAT( SUM( c.StakeWon ) , 0 )
in the order by clause instead of alias. My observation is, Alias doesn't work this way
Probably like this
SELECT a.b AS t , COUNT( c.aID ) AS r ,
COUNT(
CASE WHEN c.Finish =1
THEN 1
ELSE NULL
END ) AS wins ,
CONCAT( FORMAT( (
COUNT(
CASE WHEN c.Finish =1
THEN 1
ELSE NULL
END ) / COUNT( c.aID ) ) *100, 0 ) , '%'
) AS Percent ,
FORMAT( SUM( c.StakeWon ) , 0 ) AS stakes
FROM c
INNER JOIN a ON c.aID = a.aID
INNER JOIN d ON c.dID = d.dID
WHERE d.w >= STR_TO_DATE( '2012,07,01', '%Y,%m,%d' )
AND d.w < STR_TO_DATE( '2012,07,01', '%Y,%m,%d' ) + INTERVAL 1
MONTH
GROUP BY a.b
ORDER BY COUNT( c.aID ) AS r ,
COUNT(
CASE WHEN c.Finish =1
THEN 1
ELSE NULL
END ) AS wins ,
CONCAT( FORMAT( (
COUNT(
CASE WHEN c.Finish =1
THEN 1
ELSE NULL
END ) / COUNT( c.aID ) ) *100, 0 ) , '%'
) AS Percent ,
FORMAT( SUM( c.StakeWon ) , 0 ) DESC`