Select table two times - not working - mysql

Actually I have the following database schema:
* events
id type player match
* players
id name
* matches
id date
The event type can be "A" for assistances or "G" for goals. I need to select the two types in the same query to calculate an offensive production (assistances + goals * 2).
The final result need to be:
year player assistances goals off_production
I have tried the following query, but it's not working (it's returning wrong data):
SELECT COUNT(assist.id) AS assistances, COUNT(goals.id) AS goals, (assistances + goals * 2) AS off_prod, p.name AS player, YEAR(m.date) AS year
FROM matches AS m, players AS p, events AS assist, events AS goals
WHERE assist.match = m.id AND
assist.type ="A" AND
assist.player = p.id AND
goals.match = j.id AND
goals.type ="G" AND
goals.player = p.id
GROUP BY year, player
ORDER BY year DESC, off_prod DESC
Thanks in advance

Try this....
SELECT assistances
,goals
,(A.assistances + A.goals * 2) AS off_prod
,player
,`YEAR`
FROM (
SELECT COUNT( CASE WHEN e.`type` ='A' THEN 1 ELSE NULL END) AS assistances
,COUNT( CASE WHEN e.`type` ='G' THEN 1 ELSE NULL END) AS goals
,p.`Name` AS player
,YEAR(m.`date`) AS `year`
FROM `players` AS p
INNER JOIN `events` AS e ON p.`id` = e.`player`
INNER JOIN `matches` AS m ON e.`match` = m.`id`
GROUP BY p.`name`, YEAR(m.`date`)
) A
ORDER BY A.`year` DESC, (A.assistances + A.goals * 2) DESC
Working Sql Fiddle

Related

Return MYSQL results based on a sub query count?

Is there a way to adjust the following MYSQL query so that it only shows results where the video count is greater than 0? I have tried the following but it doesn't recognise
video_count
SELECT channels.*,
(SELECT COUNT(*) FROM videos WHERE videos.video_publisher_id = channels.channel_id) as `video_count`
FROM channels
WHERE channel_active = 1
AND video_count > 0
AND channel_thumbnail IS NOT NULL
ORDER BY channel_subscribers DESC
Move your subquery from the SELECT clause to the FROM clause. An inner join guarantees matches.
SELECT c.*, v.video_count
FROM channels c
JOIN
(
SELECT video_publisher_id, COUNT(*) AS video_count
FROM videos
GROUP BY video_publisher_id
) v ON v.video_publisher_id = c.channel_id
WHERE c.channel_active = 1
AND c.channel_thumbnail IS NOT NULL
ORDER BY c.channel_subscribers DESC;
Maybe this will help you.
SELECT channels.*,video_count.count
FROM channels
left join (SELECT channel_id,COUNT(*) count FROM videos) as `video_count` on video_count.video_publisher_id = channels.channel_id
WHERE channel_active = 1
AND video_count.count > 0
AND channel_thumbnail IS NOT NULL
ORDER BY channel_subscribers DESC
For filter by subquery result or aggregation function value you can use HAVING. You have error in WHERE clause because MySQL don't know about this column in WHERE
SELECT channels.*,
(SELECT COUNT(*) FROM videos WHERE videos.video_publisher_id = channels.channel_id) as `video_count`
FROM channels
WHERE channel_active = 1
AND channel_thumbnail IS NOT NULL
HAVING video_count > 0
ORDER BY channel_subscribers DESC
Or:
SELECT channels.*, COUNT(*) AS video_count
FROM channels
INNER JOIN videos
ON videos.video_publisher_id = channels.channel_id
WHERE channel_active = 1
AND channel_thumbnail IS NOT NULL
GROUP BY channels.channel_id
ORDER BY channel_subscribers DESC

Way to reduce execution time of this query in mysql

Some time ago I needed a little help here to build a custom query. And this query worked fine till now.
 
When I run the query (in a procedure) I get the error:
Error Code: 2013. Lost connection to MySQL server during query
My access to my.ini via ssh is read only (because my db is in a shared host "godaddy") so I can't increase the execution time (actual is 60)
Is there one way to optimize this query to make it more fast?
The query is:
SELECT #curRank := #curRank + 1 as rank, p.nick,(kills + ((p.vpos - p.vneg)*5) + (top * 5) - deaths) as score
FROM (SELECT
(SELECT uuid FROM players WHERE players.uuid = p.uuid LIMIT 1) as uuid,
(SELECT nick FROM nicks n WHERE n.pid = p.id ORDER BY id DESC LIMIT 1) as nick,
(SELECT COUNT(*) FROM kills k WHERE k.pid = p.id ) as kills,
(SELECT COUNT(*) FROM deaths d WHERE d.pid = p.id ) as deaths,
(SELECT COUNT(*) FROM headshots h WHERE h.pid = p.id ) as hs,
(SELECT COUNT(*) FROM votos vp WHERE vp.vid = p.id AND tipo="p") as vpos,
(SELECT COUNT(*) FROM votos vn WHERE vn.vid = p.id AND tipo="n") as vneg,
(SELECT COUNT(*) FROM top_rounds t WHERE t.pid = p.id ) as top,
(SELECT #curRank := 0) as rank
FROM players p
) p ORDER BY score DESC LIMIT 30;
Note: all pid's and p.id's already are indexes
Untested (due to lack of sample data):
SELECT p.nick,
(IFNULL(k.cnt, 0)
+ ((IFNULL(vpos.cnt, 0) - IFNULL(vneg.cnt, 0))*5)
+ (IFNULL(t.cnt, 0) * 5) - IFNULL(d.cnt, 0) AS score
FROM players p
LEFT JOIN (
SELECT pid, COUNT(*) AS cnt
FROM kills
GROUP BY pid
) AS k ON p.id = k.pid
⋮
LEFT JOIN (
SELECT pid, COUNT(*) AS cnt
FROM top_rounds
GROUP BY pid
) AS t ON p.id = t.pid
ORDER BY score DESC
LIMIT 30
i.e. make sure each inner query runs once only for all the players. Each subquery results in a table which maps player id to corresponding count. Since there might be zero matching rows, we have to use LEFT JOIN and translate NULL into 0 using IFNULL(foo.cnt, 0).
If you need to index rows, you can add an extra outer query for that alone, but personally I'd prefer to handle that outside SQL in the application which processes the query result.

MySQL rating/ladder system

I have two tables:
*tbl_MATCHES*
id
contestant_1
contestant_2
winner
*tbl_CONTESTANTS*
id
name
The goal is to get each contestant's win percentage. That is, count how many matches each contestant won, and divide that by the total number of matches each contestant took part in. This is currently working, but it seems cumbersome:
SELECT all_matches.contestant_id, num_matches, num_wins,
(num_wins / num_matches * 100.0) AS win_percent FROM (
// get total number of wins for each contestant
SELECT contestants.id AS contestant_id,
COUNT(matches.winner) AS num_wins
FROM contestants
LEFT JOIN matches
ON matches.winner = contestants.id
GROUP BY matches.winner
) all_matches
// join total number of wins to total number of matches played
JOIN (
SELECT contestant_id, COUNT(contestant_id) AS num_matches FROM (
// get list of all matches played by all contestants
SELECT contestants.id AS contestant_id
FROM matches
JOIN contestants ON contestants.id = matches.contestant_1
UNION ALL
SELECT contestants.id AS contestant_id
FROM matches
JOIN contestants ON contestants.id = matches.contestant_2
) all_m
GROUP BY contestant_id
) all_matches
ON all_matches.contestant_id = all_matches.contestant_id
ORDER BY win_percent DESC
I feel like this sort of thing must have been done before, and I'm looking for some help optimizing this or a link to a better one someone has already done
I would try this approach:
SELECT
contestants.id AS contestant_id,
COUNT(*) AS num_matches,
SUM( CASE WHEN matches.winner = contestants.id THEN 1 ELSE 0 END )
AS num_wins,
SUM( CASE WHEN matches.winner = contestants.id THEN 1 ELSE 0 END )
/ COUNT(*) * 100 AS win_percent
FROM matches
JOIN contestants
ON contestants.id IN( matches.contestant_1, matches.contestant_2 )
GROUP BY contestants.id

Is it possible to simplify this SQL statement with multiple subqueries and JOINs

I've spent a couple of days creating this rather complicated SQL statement, and it now gives me exactly what I want. Now I'm wondering if there is a better/simpler way to do it. Also MySQL wont let me CREATE VIEW on this statement
SELECT name, a.user, liste, c.order, total_1kr, total_5kr, total_8kr, total_10kr, total_paid, differens, sbdato, spaid, sbreg, sfdato, sforbrug, sfreg
FROM (SELECT t.user, t.paid AS spaid, t.dato AS sbdato, t.registrant AS sbreg FROM(
SELECT user,MAX(dato) AS maksdato
FROM g_kiosk_f WHERE paid!=0
GROUP BY user) AS x
JOIN g_kiosk_f AS t ON x.user =t.user
AND x.maksdato = t.dato) AS a
JOIN (SELECT s.user, (s.1kr+(s.5kr)*5+(s.8kr)*8+(s.10kr)*10) AS sforbrug, s.dato AS sfdato, s.registrant AS sfreg FROM(
SELECT user,MAX(dato) AS maksdato
FROM g_kiosk_f WHERE 1kr!=0 OR 5kr!=0 OR 8kr!=0 OR 10kr!=0
GROUP BY user) AS y
JOIN g_kiosk_f AS s ON y.user=s.user
AND y.maksdato=s.dato) AS b
JOIN (SELECT t1.name, t2.user, t1.liste, t1.order, sum( t2.1kr ) AS total_1kr, sum( t2.5kr ) *5 AS total_5kr, sum( t2.8kr ) *8 AS total_8kr, sum( t2.10kr ) *10 AS total_10kr, sum( t2.paid ) AS total_paid, ( sum( t2.1kr ) + sum( t2.5kr ) *5 + sum( t2.8kr ) *8 + sum( t2.10kr ) *10 - sum( t2.paid )) AS differens
FROM g_kiosk_users AS t1
INNER JOIN g_kiosk_f AS t2 ON t1.nr = t2.user
GROUP BY t2.user
ORDER BY t1.name ASC) AS c
ON a.user=b.user AND a.user=c.user
I have a table 'g_kiosk_f' containing id (user), date (dato), 5 kinds of transactions (1kr, 5kr, 8kr, 10kr, and paid) a cashier (registrant). Another table, 'g_kiosk_users', contains name and id (nr).
I want a result set showing
the date, registrant and amount of newest transaction where paid!=0
the date, registrant and amount of newest transaction where 1kr!=0, 5kr!=0, 8kr!=0 or 10kr!=0
the total difference of sum(1kr+5kr+8kr+10kr) and sum(paid)
So the result should look something like
Name | id | difference | newest paid date | newest paid registrant | newest paid amount | newest kr date | newest kr registrant | newest kr amount |
In the above I've included the numbers needed to do the difference calculation by hand, because it was needed at some point, but is now obsolete. Does any of this even make sense?
It seems like it should be possible to rewrite you query like this:
SELECT t1.name AS name, a.user AS user, t1.liste, t1.order,
SUM(t2.1kr) AS total_1kr, SUM(t2.5kr) * 5 AS total_5kr,
SUM(t2.8kr) AS total_8kr, SUM(t2.10kr) * 5 AS total_10kr,
SUM(52.paid) AS total_paid,
SUM(t2.1kr + 5 * tt.5kr + 8 * t2.8kr + 10 * t2.10kr)
-SUM(t2.paid) AS differens
a.dato AS sbdato, a.paid AS spaid, a.registrant as sbreg,
b.dato as sfdato,
(b.1kr+(b.5kr)*5+(b.8kr)*8+(b.10kr)*10) AS sforbrug,
b.registrant AS sfreg
FROM g_kiosk_f AS a
INNER JOIN (SELECT user, MAX(dato) FROM g_kiosk_f
WHERE paid != 0
GROUP BY user) AS a2
ON a.user = a2.user AND a.dato = a2.dato
INNER JOIN g_kiosk_f as b ON b.user = a.user
INNER JOIN (SELECT user, MAX(dato) FROM g_kiosk_f
WHERE 1kr!=0 OR 5kr!=0 OR 8kr!=0 OR 10kr!=0
GROUP BY user) AS b2
ON b.user = b2.user AND b.dato = b2.dato
INNER JOIN g_kiosk_f as t2 ON t2.user = a.user
INNER JOIN g_kiosk_users as t1 ON t1.nr = t2.user
GROUP BY a.user
ORDER BY name ASC

Help on MySQL query

I have the following table structure:
Customers - Cust_Orders - Cust_Items - Cust_Payments - Drivers
id id id id id
company cid oid oid name
driver price amount
date qty date
vat
What I want to do is showing last unpaid order marked by a specific driver id + the sum of all unpaid orders for that particular customer except the order that is already selected.
Since there might be more than one cust_items & more than one cust_payments I had to use select from select as otherwise I would have wrong sums & things got messy till I reached a point I forgot what I was doing.
Any Help would be greatly appreciated.
My current SQL which lacks the final part only (sum of other unpaid orders amounts):
SELECT `customers`.`company`,
T1.*,
ROUND( IFNULL( SUM(`cust_payments`.`amount`), 0 ), 2) AS `paid`
FROM (
SELECT `cust_orders`.*,
ROUND( IFNULL( SUM(`cust_items`.`qty` * `cust_items`.`price`), 0 ), 2) AS `total`,
SUM( ( `cust_items`.`price` * `cust_items`.`qty` * `vat` ) / 100) AS `vat`
FROM `cust_orders`
LEFT JOIN `cust_items` ON `cust_orders`.`id` = `cust_items`.`oid`
GROUP BY `cust_orders`.`id`
) `T1`
LEFT JOIN `customers` ON `T1`.`cid` = `customers`.`id`
LEFT JOIN `cust_payments` ON `T1`.`id` = `cust_payments`.`oid`
WHERE `T1`.`driver` = ? GROUP BY `T1`.`id` HAVING (`T1`.`total` - `paid`) > ?
ORDER BY `T1`.`id` DESC LIMIT 1
Can you try
SELECT
x.id,
x.company,
y.id,
y.cid,
y.driver,
y.date,
#ut:=ROUND(SUM(z.qty*z.price),2) AS unpaid_total,
#uv:=SUM((#ut*z.vat)/100) AS unpaid_vat,
#st:=ROUND(SUM(b.qty*b.price),2)-#ut AS sum_total,
SUM((#st*b.vat)/100)-#uv AS sum_vat
FROM Customers x
INNER JOIN Cust_Orders y ON x.id=y.cid
INNER JOIN Cust_Items z ON y.id=z.oid
LEFT JOIN Cust_Orders a ON x.id=a.cid
LEFT JOIN Cust_Items b ON a.id=b.oid
WHERE
y.driver=? AND
NOT EXISTS (SELECT * FROM Cust_Payments WHERE oid=y.id) AND
NOT EXISTS (SELECT * FROM Cust_Payments WHERE oid=a.id)
GROUP BY x.id,x.company, y.id, y.cid, y.driver, y.date