Query result null or 0 - mysql

I am trying to make an appointment to return all the municipalities and all the specialties .... being that even in that municipality does not have any provider for such specialty it should be listed with value 0 or null .... at the moment I am with this Query, I need some help.
select
cid.txt_cidade, esp.txt_especialidade, count(*) as QTD
from
tb_associadoespecialidade as assesp
left join
tb_especialidade as esp on esp.id_especialidade = assesp.id_especialidade
left join
tb_associado as ass on ass.id_associado = assesp.id_associado
left join
tb_cidade as cid on cid.id_cidade = ass.id_cidade
where
ass.id_categoria = 1 and txt_cidade like 'Tupã'
group by
cid.txt_cidade, esp.txt_especialidade
order by
cid.txt_cidade desc;
Diagram
Result expectancy
TXT_CIDADE ------ TXT_ESPECIALIDADE --------- count QTD
SP -------------- ESPEC01 ------------------- 10
SP -------------- ESPEC02 ------------------- 5
SP -------------- ESPEC03 ------------------- 15
RJ -------------- ESPEC01 ------------------- NULL
RJ -------------- ESPEC02 ------------------- 5
RJ -------------- ESPEC03 ------------------- NULL

Try this:
select
cid.txt_cidade, esp.txt_especialidade, count(*) as QTD
from
tb_associadoespecialidade as assesp
left join
tb_especialidade as esp on esp.id_especialidade = assesp.id_especialidade
left join
tb_associado as ass on ass.id_associado = assesp.id_associado
and ass.id_categoria = 1
left join
tb_cidade as cid on cid.id_cidade = ass.id_cidade
where
txt_cidade like 'Tupã'
group by
cid.txt_cidade, esp.txt_especialidade
order by
cid.txt_cidade desc;
When you apply a where clause on a field from a table that is outer joined, you risk unintentionally throwing away records. By putting your desired filtering in the join condition, you still get null values where that criteria is not met. See my answer here for more details.

Related

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

difference made by sub-queries

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

Mysql query to filter result

I have 2 tables
TBL 1: property TBL 2: property_detail
--------------------- --------------------------------------
Id Name status property_id param value
--------------------- --------------------------------------
1 X 1 1 parking two-wheeler
2 Y 1 1 furnishing furnished
3 Z 0 2 parking car-parking
4 A 1 2 furnishing semi-furnished
5 B 1 3 furnishing furnished
6 C 0 4 parking car-parking
"property_id" column in "property_detail" is foreign key of "Id" column in "property"
I want search result for status=1 and (param="parking" and value="car-parking") and (param="furnishing" and value="furnished")
From above Example table, the result will be
Result
-------------
id name
-------------
2 Y
How to achieve this?
you can get your desired result set by using join twice with details table
select p.*
from property p
join property_detail d on (p.Id = d.property_id)
join property_detail d1 on (p.Id = d1.property_id)
where p.status=1
and d.param='parking' and d.value='car-parking'
and d1.param='furnishing' and d1.value='semi-furnished';
Another way you can also use below query using having clause and sum function
select p.*
from property p
join property_detail d on (p.Id = d.property_id)
where p.status=1
group by p.Id
having sum(param="parking" and value="car-parking")
and sum(param="furnishing" and value="semi-furnished")
DEMO
SELECT property.id, property.name
FROM property INNER JOIN property_detail
ON property.id = property_detail.property_id
WHERE
(`param`="parking" AND `value`="car-parking")
AND
(`param`="furnishing" AND `value`="furnished")
AND status = 1;
can you try this one? I'm not sure though.. but it'll give you an idea.

MySQL JOIN returns unexpected values

I'm trying to do a simple mysql request and I'm having problems.
I have 2 tables defined like below:
currencies
______________________________________________________________________________________
currency_id | currency_name | currency_symbol | currency_active | currency_auto_update
exchange_rates
____________________________________________________________________________________________________
exchange_rate_id | currency_id | exchange_rate_date | exchange_rate_value | exchange_rate_added_date
What I want to do is to select the last row inside exchange_rates for the active currency.
I did it like this:
SELECT c.currency_id, c.currency_name, c.currency_symbol, c.currency_active, er.exchange_rate_id, er.exchange_rate_date, er.exchange_rate_value
FROM currencies c
LEFT JOIN (
SELECT er1.exchange_rate_id, er1.currency_id, er1.exchange_rate_date, er1.exchange_rate_value
FROM exchange_rates er1
ORDER BY er1.exchange_rate_date DESC
LIMIT 1
) AS er
ON er.currency_id=c.currency_id
WHERE c.currency_active='1'
This is returning me NULL values from the exchange_rates table, even if there are matching rows
I've tried to remove LIMIT 1 but if I do it like this is returning me all the rows for active currency, which is not the solution I want
How should this query look like?
Thanks!
Try this:
SELECT c.currency_id, c.currency_name, c.currency_symbol, c.currency_active, er.exchange_rate_id, er.exchange_rate_date, er.exchange_rate_value
FROM currencies c
LEFT JOIN (SELECT * FROM
(SELECT er1.exchange_rate_id, er1.currency_id, er1.exchange_rate_date, er1.exchange_rate_value
FROM exchange_rates er1
ORDER BY er1.exchange_rate_date DESC) AS A GROUP BY currency_id
) AS er
ON er.currency_id=c.currency_id
WHERE c.currency_active='1'
The idea of query look correct to me. your left join query should return the row with the newest exchange rate. you could use inner join here because there must be a currency refering to this...
SELECT c.currency_id, c.currency_name, c.currency_symbol, c.currency_active, er.exchange_rate_id, er.exchange_rate_date, er.exchange_rate_value
FROM currencies c
INNER JOIN exchange_rates_er1 e ON e.currency_id = c.currency_id
WHERE c.currency_active='1'
ORDER BY e.exchange_rate_date DESC
LIMIT 1

Display null for column if no row found

I currently have the following SQL statement:
SELECT s.first_name, s.last_name, tgs.group_identifier
FROM staff s
JOIN staff_training st
ON s.staff_id = st.staff_id
JOIN training_group_staff tgs
ON st.staff_training_id = tgs.staff_training_id
WHERE st.staff_course_id = '164'
training_group_staff only contains the staff_training_id and training_group_id
This statement works as expected and returns all staff names attending course 164 AND have been placed into a group (identified with the group_identifier field).
What I am attempting to do is display all users on training course 164 and if no group selected (there won't be a row for the specific staff_training_id in training_group_staff) then return null for that column.
Visual Example
Current Statement Returns:
first_name | last_name | group_identifier
Jim | Jones | 3
Harry | Jones | 6
What I am attempting to return is:
first_name | last_name | group_identifier
Jim | Jones | 3
Harriet | Smith | NULL // No row in training_group_staff
Harry | Jones | 6
I have tried several joins, however seem to return the same results - is the desired output possible in one query?
Try with LEFT JOIN. Should be what you're after.
Use outer joins when you want to include NULLs following JOIN operations:
SELECT s.first_name, s.last_name, tgs.group_identifier
FROM staff s
JOIN staff_training st
JOIN ON s.staff_id = st.staff_id
LEFT OUTER JOIN training_group_staff tgs
ON st.staff_training_id = tgs.staff_training_id
WHERE st.staff_course_id = '164'
Two things:
Try using an explicit LEFT JOIN when joining the training_group_staff table
An IF statement checking to see if the value is empty and setting it to null
SELECT s.first_name
, s.last_name
, IF(tgs.group_identifier = '', null, group_identifier) AS group_identifier
FROM staff s
JOIN staff_training st
ON s.staff_id = st.staff_id
LEFT JOIN training_group_staff tgs
ON st.staff_training_id = tgs.staff_training_id
WHERE sm.staff_course_id = '164'