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.
Related
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.
help. I have this query in mysql. What it does is combine fields from three tables. One field (Duration (h)) it subtracts the end time and start time. May time data is in the form of time only and not date time. So I decided to use timediff function. This runs well for time within the same day. But not time differences like 00:00 - 23:30; in this case I get the answer -23.5. What can I do to correct this. Thanks in advance.
SELECT `tblproductiondata`.`productionDay` , `tbllinestoppagecategories`.`category` , `tblshifts`.`ID` , `tblstoppagedescriptions`.`endTime` , `tblstoppagedescriptions`.`startTime` , IFNULL( ROUND( `tblstoppagedescriptions`.`duration(mins)` /60, 2 ) , ROUND( (
TIME_TO_SEC( TIMEDIFF( `tblstoppagedescriptions`.`endTime` , `tblstoppagedescriptions`.`startTime` ) ) /3600 ) , 2 )
) AS `Duration (h)`
FROM (
`tbllinestoppagecategories`
INNER JOIN `tblstoppagereasons` ON `tbllinestoppagecategories`.`categoryID` = `tblstoppagereasons`.`stoppagecategory`
)
INNER JOIN (
`tblshifts`
INNER JOIN (
`tblproductiondata`
INNER JOIN `tblstoppageDescriptions` ON `tblproductiondata`.`productionID` = `tblstoppagedescriptions`.`prodDate`
) ON `tblshifts`.`ID` = `tblproductiondata`.`shiftName`
) ON `tblstoppageReasons`.`resID` = `tblstoppagedescriptions`.`stoppageReason`
WHERE (
(
(
`tbllinestoppagecategories`.`category`
) <> "Changeover Maintenance Activities"
)
)
ORDER BY `tblproductiondata`.`productionDay` ASC
try
TIME_TO_SEC(
TIMEDIFF(
CONCAT(tblproductiondata.productionDay, ' ', tblstoppagedescriptions.endTime),
CONCAT(tblproductiondata.productionDay, ' ', `tblstoppagedescriptions`.`startTime`)
)
)
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.
Im trying to calculate the amount of money won by all the offspring of a male race horse (Sire) over a time period. Listed by the Sire with the most amount of money won.
I run the query and get the result Im after with one problem, I cant display the sires name, only their ID.
SELECT `horses`.`SireID` AS `SireID` , `horses`.`HorseName` AS `Sire Name`,
COUNT( `runs`.`HorsesID` ) AS `Runs` ,
COUNT(
CASE WHEN `runs`.`Finish` =1
THEN 1
ELSE NULL
END ) AS `Wins` ,
CONCAT( FORMAT( (
COUNT(
CASE WHEN `runs`.`Finish` =1
THEN 1
ELSE NULL
END ) / COUNT
( `runs`.`TrainersID` ) ) *100, 0 ) , '%'
) AS `Percent` ,
FORMAT( SUM( `runs`.`StakeWon` ) , 0 ) AS `Stakes`
FROM runs
INNER JOIN horses ON runs.HorsesID = horses.HorsesID
INNER JOIN races ON runs.RacesID = races.RacesID
WHERE `races`.`RaceDate` >= STR_TO_DATE( '2012,07,01', '%Y,%m,%d' )
AND `races`.`RaceDate` < STR_TO_DATE( '2012,07,01', '%Y,%m,%d' ) + INTERVAL 1
MONTH
AND `horses`.`SireID` <> `horses`.`HorsesID`
GROUP BY `horses`.`SireID`, `horses`.`HorseName`
ORDER BY SUM( `runs`.`StakeWon` ) DESC
Take a record in the horse table for example, a horse has a horsesID and they also have a sireID (their father). The sireID has an equivalent horsesID in another record in the same table as it is also a horse
Basically I need to map the horseName to the sireID.
I thought a self join would work.
`AND `horses`.`SireID` <> `horses`.`HorsesID``
but it doesn't return the correct Sire name corresponding to the SireID.
You can do a JOIN on the table itself. Here's a simpler example:
SELECT Horses.HorseID, Horses.HorseName, Horses.SireID, b.HorseName as SireName
FROM Horses
LEFT JOIN Horses b ON (Horses.SireID = b.HorseID)
You can probably figure out how to add the conditions from here.
join horses sires on sires.HorsesID = horses.SireID
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`