difference made by sub-queries - mysql

Problem statement link
Correct code (by dongyuzhang):
select con.contest_id,
con.hacker_id,
con.name,
sum(total_submissions),
sum(total_accepted_submissions),
sum(total_views), sum(total_unique_views)
from contests con
join colleges col on con.contest_id = col.contest_id
join challenges cha on col.college_id = cha.college_id
left join
(select challenge_id, sum(total_views) as total_views, sum(total_unique_views) as total_unique_views
from view_stats group by challenge_id) vs on cha.challenge_id = vs.challenge_id
left join
(select challenge_id, sum(total_submissions) as total_submissions, sum(total_accepted_submissions) as total_accepted_submissions from submission_stats group by challenge_id) ss on cha.challenge_id = ss.challenge_id
group by con.contest_id, con.hacker_id, con.name
having sum(total_submissions)!=0 or
sum(total_accepted_submissions)!=0 or
sum(total_views)!=0 or
sum(total_unique_views)!=0
order by contest_id;
My changed code without sub-queries which is incorrect and giving larger values of sums. I don't understand how writing sub-queries is making the difference ? A simple example test case would be very helpful. THANKS !
select con.contest_id,
con.hacker_id,
con.name,
sum(total_submissions),
sum(total_accepted_submissions),
sum(total_views), sum(total_unique_views)
from contests con
join colleges col on con.contest_id = col.contest_id
join challenges cha on col.college_id = cha.college_id
left join view_stats vs
on cha.challenge_id = vs.challenge_id
left join submission_stats ss
on cha.challenge_id = ss.challenge_id
group by con.contest_id, con.hacker_id, con.name
having sum(total_submissions)!=0 or
sum(total_accepted_submissions)!=0 or
sum(total_views)!=0 or
sum(total_unique_views)!=0
order by contest_id;

In general with the subqueries first you make the aggregation before the join, so the values are right, since you have only one row per chalange_id respective contest_id and hacker id with the right sum.
If you join them together first, the values are summed up once for every matching row in the main-query.
Table1:
id | value1
a | 1
a | 2
b | 3
Table2:
id | value2
a | 5
a | 6
If you join without subqueries you got(before grouping)
a | 1 | 5
a | 1 | 6
a | 2 | 5
a | 2 | 6
So surely the sums are wrong.
select Table1.id , sum(value1), sum(value2) from
Table1 join Table2 on Table1.id = Table2.id
would return
a | 6 | 22
but
select Table1.id , sum(value1), max(sum2) from
Table1 join (select sum(value2) as sum2 from Table2 group by id) t2 on Table1.id = Table2.id
would return
a | 3 | 11
I don't know if this is the case in your query, but this is the main difference of using subqueries

Related

How to create a select query that ignores rows that have a certain reference to a 3rd table? [duplicate]

This question already has answers here:
Return row only if value doesn't exist
(2 answers)
Closed 1 year ago.
I have three tables, let's say they are fruit, fruit_data and data. A row in the fruit table may have 0-n data references, and these are made using the fruit_data table:
fruit fruit_data data
----------------------------------------------
| fruit_id | fruit_id | data_id |
| ... | data_id | name |
| ... | | ... |
I'd like to select all fruit.fruit_ids that do not have a reference to a data row where data.name is "glass".
I've come up with:
SELECT DISTINCT fruit.fruit_id
FROM fruit
JOIN fruit_data ON fruit_data.fruit_id = fruit.fruit_id
JOIN data ON data.data_id = fruit_data.data_id
WHERE data.name != 'glass';
but this seems to exclude fruit rows that do not have any references to data.
So, how to write a query that returns all fruit_ids that either don't have any data rows or that only have data rows where data.name != "glass"?
One method is left joins and group by:
SELECT f.fruit_id
FROM fruit f LEFT JOIN
fruit_data fd
ON fd.fruit_id = f.fruit_id LEFT JOIN
data d
ON d.data_id = fd.data_id
GROUP BY f.fruit_id
HAVING SUM(CASE WHEN d.name = 'glass' THEN 1 ELSE 0 END) = 0;
But I think not exists is a more sensible method:
SELECT f.fruit_id
FROM fruit f
WHERE NOT EXISTS (SELECT 1
FROM fruit_data fd
data d
ON d.data_id = fd.data_id
WHERE fd.fruit_id = f.fruit_id AND
d.name = 'glass'
);
You could use the not exists operator:
SELECT *
FROM fruit f
WHERE NOT EXISTS (SELECT *
FROM fruit_data fd
JOIN data d ON fd.data_id = d.data.id
WHERE fd.fruit_id = f.fruit_id AND
d.name = 'glass')

SQL Distinct based on different colum

I have problem to distinct values on column based on other column. The case study is:
Table: List
well | wbore | op|
------------------
wella|wbore_a|op_a|
wella|wbore_a|op_b|
wella|wbore_a|op_b|
wella|wbore_b|op_c|
wella|wbore_b|op_c|
wellb|wbore_g|op_t|
wellb|wbore_g|op_t|
wellb|wbore_h|op_k|
So, I want the output to be appear in different field/column like:
well | total_wbore | total_op
----------------------------
wella | 2 | 3
---------------------------
wellb | 2 | 2
the real study case come from different table but to simplify it I just assume this case happened in 1 table.
The sql query that I tried:
SELECT well.well_name, wellbore.wellbore_name, operation.operation_name, COUNT(*)
FROM well
INNER JOIN wellbore ON wellbore.well_uid = well.well_uid
INNER JOIN operation ON wellbore.well_uid = operation.well_uid
GROUP BY well.well_name,wellbore.wellbore_name
HAVING COUNT(*) > 1
But this query is to calculate the duplicate row which not meet the requirement. Anyone can help?
you need to use count distinct
SELECT
count(distinct wellbore.wellbore_name) as total_wbore
count(distinct operation.operation_name) as total_op
FROM well
INNER JOIN wellbore ON wellbore.well_uid = well.well_uid
INNER JOIN operation ON wellbore.well_uid = operation.well_uid
Final query:
SELECT
well.well_name,
COUNT(DISTINCT wellbore.wellbore_name) AS total_wbore,
COUNT(DISTINCT operation.operation_name) AS total_op
FROM well
INNER JOIN wellbore ON wellbore.well_uid = well.well_uid
INNER JOIN operation ON wellbore.well_uid = operation.well_uid
GROUP BY well.well_name

Unique rows in join result

I have a tables of delas and curencies look like this
curecnies
id,code
pairs (the available pairs of curencies )
id to_sell to_buy
deals
id
user_id
pair_id
amount_to_sell
amount_to_buy
So I need to get all match deals which can execute , but I am can not get the unique matches.
Here is my sql query
select *
from deals as d1
join deals d2
on d1.sell_amount = d2.buy_amount and d1.buy_amount = d2.sell_amount
i am getting result look like this
id | user_id | pair_id | amount_to_buy | amount_to_sell | id | user_id | pair_id | amount_to_buy | amount_to_sell
1|2|1|1000|3000|2|1|2|3000|1000
2|1|2|3000|1000|1|2|1|1000|3000
You may try using a least/greatest trick here:
SELECT t1.*, t2.*
FROM
(
SELECT DISTINCT
LEAST(d1.id, d2.id) AS d1_id,
GREATEST(d1.id, d2.id) AS d2_id
FROM deals AS d1
INNER JOIN deals d2
ON d1.sell_amount = d2.buy_amount AND
d1.buy_amount = d2.sell_amount
) d
INNER JOIN deals t1
ON d.d1_id = t1.id
INNER JOIN deals t2
ON d.d2_id = t2.id;
The basic idea here is that the subquery labelled d finds a single pair of matched deal IDs, using a least/greatest trick. Then, we join twice to the deals table again to bring in the full information for each member of that deal pair.

how to show 2 value and one values count from 3 table using mysql

I have 3 tables
Table1 (theoryquestion)
id | question | mark | technology
Table2 (mark)
mark | id
Table3 (technologies)
technology | id
I want to select count of question from corresponding mark and tech,
I have tried this
SELECT m.mark_name
, t.techname
, COUNT(q.question)
FROM question_mark m
JOIN theoryquestion q
on q.mark = m.mark_name
and q.technology = t.techname
JOIN technologies
You should use a proper on clause for join the table technologies
and use group by for trigger the aggregation function (count)
SELECT
question_mark.mark_name
,technologies.techname
,COUNT(theoryquestion.question)
FROM question_mark
INNER JOIN theoryquestion on theoryquestion.mark=question_mark.mark_name
INNER JOIN technologies theoryquestion.technology=technologies.techname
GROUP BY question_mark.mark_name ,technologies.techname
this worked for me..........
thank zzz
SELECT question_mark.mark_name,technologies.techname,COUNT(theoryquestion.question) FROM theoryquestion INNER JOIN question_mark on theoryquestion.mark=question_mark.mark_name INNER JOIN technologies on theoryquestion.technology=technologies.techname GROUP BY question_mark.mark_name ,technologies.techname

MySQL JOIN+COUNT+WHERE+AND

I have table of regions:
table region:
id | title
Region has many adverts:
table advert:
id | region_id | ...
Then advert has many uses (many-many through table adv_use):
table use:
use | slug | ...
----------------
1 | slug_1 | ...
2 | slug_2 | ...
..................
table adv_use:
adv_id | use_id
I want select all regions with count(*) of adverts, which have uses with slug_1 AND slug_2. If advert has no use with slug_1 or with slug_2 (or both), it's must not be counted.
What i have now:
SELECT COUNT(DISTINCT advert.id) as count
FROM region
JOIN advert ON region.id = advert.region_id
JOIN adv_use ON advert.id = adv_use.adv_id
JOIN use ON adv_use.use_id = use.id
WHERE use.slug IN ('slug_1', 'slug_2')
GROUP BY region.id
HAVING COUNT(DISTINCT adv_use.use_id) = 2
But it's working not as i want.
SQLFiddle: http://sqlfiddle.com/#!2/5b4d4/1
Thanks for help and sorry for bad english.
You need to use a subquery to select the adv_id that use both slugs:
SELECT COUNT(DISTINCT advert.id) as count, region.id as reg_id
FROM region
JOIN advert ON region.id = advert.region_id
JOIN (SELECT adv_use.adv_id
FROM adv_use
JOIN tbl_use ON adv_use.use_id = tbl_use.id
WHERE tbl_use.slug IN ('slug1', 'slug2')
GROUP BY adv_use.adv_id
HAVING COUNT(DISTINCT adv_use.use_id) = 2) adv_use
ON advert.id = adv_use.adv_id
GROUP BY region.id
;
SQLFIDDLE