Let's take this table for an example...
m_tid | m_tid2 | m_hteam_score | m_ateam_score
2 5 69 30
5 2 0 5
I'm bad at custom making tables, sorry...
So let's take this data, now m_tid and m_tid2 are columns for TID's that are in a separate table of their own.
Now what I want to do, is collect the score for team id2 (or team id1) of all the scores... How would I count two columns for whether or not the team is on m_tid and m_tid2
I don't have a query made, but I wouldn't know how I would go about making a query for this anyways. :(
The expected results would be something like this
m_tid | m_tid_score | m_tid2 | m_tidscore2
5 35 2 69
If you want to get the total score for each team, here is one method using correlated subqueries:
select t.*,
(coalesce((select sum(s.m_hteam_score) from scores s where s.m_tid = t.tid), 0) +
coalesce((select sum(s.m_ateam_score) from scores s where s.m_tid2 = t.tid), 0)
) as totalscore
from teams t;
Here's another option using conditional aggregation:
select o.id, sum(case when y.m_tid = o.id then y.m_hteam_score
when y.m_tid2 = o.id then y.m_ateam_score
else 0 end) score
from othertable o
join yourtable y on o.id in (y.m_tid, y.m_tid2)
group by o.id
Related
I have a table with 1v1 matches like this:
match_number|winner_id|loser_id
------------+---------+--------
1 | 1 | 2
2 | 2 | 3
3 | 1 | 2
4 | 1 | 4
5 | 4 | 1
and I would like to get something like this:
player|matches_won|matches_lost
------+-----------+------------
1 | 3 | 1
2 | 1 | 2
3 | 0 | 1
4 | 1 | 1
My MySQL Query looks like this
SELECT win_matches."winner_id" player, COUNT(win_matches."winner_id") matches_won, COUNT(lost_matches."loser_id") matches_lost FROM `matches` win_matches
JOIN `matches` lost_matches ON win_matches."winner_id" = lost_matches."winner_id"
I don't know what I did wrong, but the query just loads forever and doesn't return anything
You want to unpivot and then aggregate:
select player_id, sum(is_win), sum(is_loss)
from ((select winner_id as player_id 1 as is_win, 0 as is_loss
from t
) union all
(select loser_id, 0, 1
from t
)
) wl
group by player_id;
Your query is simply not correct. The two counts will produce the same same value -- COUNT(<expression>) returns the number of non-NULL rows for that expression. Your two counts return the same thing.
The reason it is taking forever is because of the Cartesian product problem. If a player has 10 wins and 10 losses, then your query produces 100 rows -- and this gets worse for players who have played more often. Processing all those additional rows takes time.
If you have a separate players table, then correlated subqueries may be the fastest method:
select p.*,
(select count(*) from t where t.winner_id = p.player_id) as num_wins,
(select count(*) from t where t.loser_id = p.player_id) as num_loses
from players p;
However, this requires two indexes for performance on (winner_id) and (loser_id). Note these are separate indexes, not a single compound index.
You are joining the same table twice.
Both the alias win_matches and lost_matches are on the table matches, causing your loop.
You probably don't need separate tables for win and losses, and could do both in the same table by writing one or zero in a column for each.
I don't to change your model too much and make it difficult to understand, so here is a slight modification and what it could look like:
SELECT m."player_id" player,
SUM(m."win") matches_won,
SUM(m."loss") matches_lost
FROM `matches` m
GROUP BY player_id
Without a join, all in the same table with win and loss columns. It looked to me like you wanted to know the number of win and loss per player, which you can do with a group by player and a sum/count.
I have two database tables:
***aff_purchases***
id | affiliate_id | payout
1 | 12 | 50.00
2 | 12 | 10.00
3 | 12 | 50.00
4 | 12 | 10.00
***aff_payments***
id | affiliate_id | amount_paid
8 | 12 | 50.00
I would like to return an array of all affiliate IDs where the 'payout' total is 50 or more than the 'amount_paid' for an affiliate ID.
I think that I need to SUM together the columns and then compare, but I am struggling to understand how. Please see my efforts below:
SELECT
(SELECT SUM(amount_paid) FROM exp_cdwd_aff_payments AS pay WHERE pay.affiliate_id = 12) AS 'amount_paid'
(SELECT SUM(payout) FROM exp_cdwd_aff_purchases AS pur WHERE pur.affiliate_id = 12) AS 'payout'
FROM
exp_cdwd_aff_payments AS pay
WHERE
payout > amount_paid
One approach here is to use join two separate subqueries which find the payout and payment totals. Then, compare each affiliate_id to see if meets your requirement.
SELECT
t1.affiliate_id
FROM
(
SELECT affiliate_id, SUM(amount_paid) AS amount_paid_total
FROM aff_payments
GROUP BY affiliate_id
) t1
LEFT JOIN
(
SELECT affiliate_id, SUM(payout) AS payout_total
FROM aff_purchases
GROUP BY affiliate_id
) t2
ON t1.affiliate_id = t2.affiliate_id
WHERE COALESCE(t2.payout_total, 0) > t1.amount_paid_total + 50
Note that affiliates who have a payout, but have not paid, would not appear in the result set.
The problem is that you cannot use aliases defined in the SELECT in the WHERE. In most databases, you would use a CTE or subquery. However, MySQL does not support CTEs and it imposes overhead on subqueries (by materializing them).
So, MySQL has overloaded the HAVING clause, to allow it to be used in non-aggregation queries. You can do what you want using HAVING:
SELECT a.affiliate_id,
(SELECT SUM(cap.amount_paid) FROM exp_cdwd_aff_payments cap WHERE cap.affiliate_id = a.affiliate_id) AS amount_paid
(SELECT SUM(pur.payout) FROM exp_cdwd_aff_purchases pur WHERE pur.affiliate_id = a.affiliate_id) AS payout
FROM affiliates a
HAVING payout > amount_paid;
The above assumes you have a table with one row per affiliate_id. It uses this via a correlated subquery. Also note the use of table aliases and qualified column names.
I have a table like this:
userid | trackid | path
123 70000 ad
123 NULL abc.com
123 NULL Apply
345 70001 Apply
345 70001 Apply
345 NULL Direct
345 NULL abc.com
345 NULL cdf.com
And I want a query like this. When path='abc.com', num_website +1; when path='Apply', num_apply +1
userid | num_website | num_Apply | num_website/num_Apply
123 1 1 1
345 1 2 0.5
My syntax looks like this:
select * from
(select userid,count(path) as is_CWS
from TABLE
where path='abc.com'
group by userid
having count(path)>1) a1
JOIN
(select userid,count(userid) as Apply_num from
where trackid is not NULL
group by userid) a2
on a1.userid=a2.userid
My question is
1. how to have the field num_website/num_apply in term of my syntax above?
2. is there any other easier way to get the result I want?
Any spots shared will appreciate.
The simplest way to do it would be to change the select line:
SELECT a1.userid, a1.is_CWS, a2.Apply_num, a1.is_CWS/a2.Apply_num FROM
(select userid,count(path) as is_CWS
from TABLE
where path='abc.com'
group by userid
having count(path)>1) a1
JOIN
(select userid,count(userid) as Apply_num
from TABLE
where trackid is not NULL
group by userid) a2
on a1.userid=a2.userid
and then continue with the rest of your query as you have it. The star means "select everything." If you wanted to select only a few things, you would just list those things in place of the star, and if you wanted to select some other values based on those things, you would put those in the stars as well. In this case a1.is_CWS/a2.Apply_num is an expression, and MySql knows how to evaluate it based on the values of a1.is_CWS and a2.Apply_num.
In the same vein, you can do a lot of what those subqueries are doing in a single expression instead of a subquery. objectNotFound has the right idea. Instead of doing a subquery to retrieve the number of rows with a certain attribute, you can select SUM(path="abc.com") as Apply_num and you don't have to join anymore. Making that change gives us:
SELECT a1.userid,
SUM(path="abc.com") as is_CWS,
a2.Apply_num,
is_CWS/a2.Apply_num FROM
TABLE
JOIN
(select userid,count(userid) as Apply_num
FROM TABLE
where trackid is not NULL
group by userid) a2
on a1.userid=a2.userid
GROUP BY userid
Notice I moved the GROUP BY to the end of the query. Also notice instead of referencing a1.is_CWS I now reference just is_CWS (it's no longer inside the a1 subtable so we can just reference it)
You can do the same thing to the other subquery then they can share the GROUP BY clause and you won't need the join anymore.
to get you started ... you can build on top of this :
select
userid,
SUM(CASE WHEN path='abc.com'then 1 else 0 end ) as num_website,
SUM(CASE WHEN path='Apply' and trackid is not NULL then 1 else 0 end ) as Apply_Num
from TABLE
WHERE path='abc.com' or path='Apply' -- may not need this ... play with it
group by userid
I need a Full Outer Join in mysql. I found a solution here: Full Outer Join in MySQL My problem is that t1 and t2 are subqueries themselves. So resulting query looks like a monster.
What to do in this situation? Should I use views instead of subqueries?
Edit:
I'll try to explain a bit more. I have orders and payments. One payment can cower multiple orders, and one order can be cowered by multiple payments. That is why I have tables orders, payments, and paymentitems. Each order has field company (which made this order) and manager (which accepted this order). Now I need to group orders and payments by company and manager and count money. So I want to get something like this:
company1 | managerA | 200 | 200 | 0
company1 | managerB | Null | 100 | 100
company1 | managerC | 300 | Null | -300
company2 | managerA | 150 | Null | -150
company2 | managerB | 100 | 350 | 250
The query, I managed to create:
SELECT coalesce(o.o_company, p.o_company)
, coalesce(o.o_manager, p.o_manager)
, o.orderstotal
, p.paymentstotal
, (coalesce(p.paymentstotal, 0) - coalesce(o.orderstotal, 0)) AS balance
FROM
(((/*Subquery A*/SELECT orders.o_company
, orders.o_manager
, sum(o_money) AS orderstotal
FROM
orders
WHERE
(o_date >= #startdate)
AND (o_date <= #enddate)
GROUP BY
o_company
, o_manager) AS o
LEFT JOIN (/*Subquery B*/SELECT orders.o_company
, orders.o_manager
, sum(paymentitems.p_money) AS paymentstotal
FROM
((payments
INNER JOIN paymentitems
ON payments.p_id = paymentitems.p_id)
INNER JOIN orders
ON paymentitems.p_oid = orders.o_id)
WHERE
(payments.p_date >= #startdate)
AND (payments.p_date <= #enddate)
GROUP BY
orders.o_company
, orders.o_manager) AS p
ON (o.o_company = p.o_company) and (o.o_manager = p.o_manager))
union
(/*Subquery A*/
right join /*Subquery B*/
ON (o.o_company = p.o_company) and (o.o_manager = p.o_manager)))
This is simplified version of my query. Real query is much more complex, that is why I want to keep it as simple as it can be. Maybe even split in to views, or may be there are other options I am not aware of.
I think the clue is in "group orders and payments by company". Break the outer join into a query on orders and another query on payments, then add up the type of money (orders or payments) for each company.
If you are trying to do a full outer join and the relationship is 1-1, then you can accomplish the same thing with a union and aggreagation.
Here is an example, pulling one column from two different tables:
select id, max(col1) as col1, max(col2) as col2
from ((select t1.id, t1.col1, NULL as col2
from t1
) union all
(select t23.id, NULL as col1, t2.col2
from t2
)
) t
group by id
I have a mysql table with actions and question_ids. Each action comes with a score like this:
ACTION | SCORE
downvote_question | -1
upvote_question | +1
in_cardbox | +2
I want to query for the question with the highest score but I can't figure it out.
http://sqlfiddle.com/#!2/84e26/15
So far my query is:
SELECT count(*), l1.question_id, l1.action
FROM `log` l1
GROUP BY l1.question_id, l1.action
which gives me every question_id with all its accumulated actions.
What I want is this:
QUESTION_ID | SCORE
2 | 5
1 | 4
3 | 1
4 | 1
5 | 1
I can't figure it out - I probably need subqueries, JOINS or UNIONS...
Maybe you can try this one.
SELECT a.question_id, sum(b.score) totalScore
FROM `log` a INNER JOIN scoreValue b
on a.`action` = b.actionname
group by a.question_id
ORDER BY totalScore DESC
SQLFiddle Demo
You should replace count(*) with sum(l1.score) because sum will add all values based on group by statement
SELECT sum(l1.score), l1.question_id, l1.action
FROM `log` l1
GROUP BY l1.question_id, l1.action
With constant scores works on SQL Fiddle (with grouping by question):
SELECT
sum(
CASE WHEN l1.action = 'downvote_question' THEN -1
WHEN l1.action = 'upvote_question' THEN 1
ELSE 2 END
) score,
l1.question_id
FROM `log` l1
GROUP BY l1.question_id
SELECT sum(SCORE), l1.question_id, l1.action
FROM `log` l1
GROUP BY l1.question_id, l1.action
is it what you want to?
upd: in your code on fidel, there is no such column as score, but i think it wont be a problem to create a tabel with action | score and join it to sum(score)