Count with LEFT JOIN shows only one row - mysql

I have the following data in my database:
scu_banks:
---------------------------------
| id | type | name |
|-------------------------------|
| 1 | 1 | One |
| 2 | 1 | Two |
| 3 | 2 | Three |
| 4 | 3 | Four |
---------------------------------
scu_statement:
---------------------------------
| id | code | status |
|-----------------------------------|
| 1 | 1 | 0 |
| 2 | 1 | 1 |
| 3 | 2 | 0 |
| 4 | 1 | 0 |
-------------------------------------
What I want to do is I want to select all the rows in table scu_banks and calculate how many rows I have with the status 0. The data should be represented like:
--------------------------------------------------------------
| scu_banks.type | scu_banks.name | status | scu_banks.id |
--------------------------------------------------------------
| 1 | One | 2 | 1 |
| 1 | Two | 0 | 2 | //There is no row with status 0
| 2 | Three | 0 | 3 |
| 3 | Four | 0 | 4 |
--------------------------------------------------------------
When I run my sql statement I get the following data:
---------------------------------------------------------------
| scu_banks.type | scu_banks.name | status | scu_banks.id |
--------------------------------------------------------------
| 1 | One | 2 | 1 |
---------------------------------------------------------------
The data I get in this case is correct. 2 it the total count of all the rows in table scu_statement. The statement also dont shows the other rows in the database.
Does someone know what is wrong with my sql statement?
Here is my sql statement:
SELECT b.type 'scu_banks.type',
b.name 'scu_banks.name',
count(y.status) 'status',
b.id 'scu_banks.id'
FROM scu_banks b
LEFT JOIN (SELECT s.code, count(s.status) status
FROM scu_bankstatement s
WHERE status='0'
GROUP BY s.code) y
ON y.code = b.id

You need a GROUP BY in your outer query, otherwise the query simply counts status for all banks. You can also simplify your query by just LEFT JOINing the two tables on code/id and status = 0
SELECT b.type `scu_banks.type`,
b.name `scu_banks.name`,
COUNT(s.status) `status`,
b.id `scu_banks.id`
FROM scu_banks b
LEFT JOIN scu_statement s ON s.code = b.id AND s.status = 0
GROUP BY b.id, b.name, b.type
Output
scu_banks.type scu_banks.name status scu_banks.id
1 One 2 1
1 Two 1 2
2 Three 0 3
3 Four 0 4
Demo on dbfiddle

Related

Joining multiple rows with same ID in one

I am having trouble with an SQL query. I have two tables.
My first table:
+------------+-------------+---------------+
| id_mission | Some column | Other column |
+------------+-------------+---------------+
| 1 | ... | ... |
| 2 | ... | ... |
+------------+-------------+---------------+
My second table:
+------------+-------------+---------+
| id_mission | id_category | points |
+------------+-------------+---------+
| 1 | 1 | 3 |
| 1 | 2 | 4 |
| 1 | 3 | 4 |
| 1 | 4 | 8 |
| 2 | 1 | -4 |
| 2 | 2 | 3 |
| 2 | 3 | 1 |
| 2 | 4 | -7 |
+------------+-------------+---------+
And I would like to have this kind of result with my SELECT request
+------------+-------------+--------------+---------------+----------------+
| id_mission | Some column | Other column | id_category 1 | id_category X |
+------------+-------------+--------------+---------------+----------------+
| 1 | ... | ... | ... | ... |
| 2 | ... | ... | ... | ... |
+------------+-------------+--------------+---------------+----------------+
I have tried this with the first two column but it doesn't work, I also tried GROUP_CONCAT, it works but it's not the result I want.
SELECT m.id_mission ,mc.id_category 1,mc1.id_category 2
from mission m
left join mission_category mc on m.id_mission = mc.id_mission
left join mission_category mc1 on m.id_mission = mc1.id_mission
Can someone help me?
You can use conditional aggregation. Assuming that you want to pivot the points value per category:
select
t1.*,
max(case when t2.id_category = 1 then points end) category_1,
max(case when t2.id_category = 2 then points end) category_2,
max(case when t2.id_category = 3 then points end) category_3
from t1
inner join t2 on t2.id_mission = t1.id_mission
group by t1.id_mission
This assumes that id_mission is the primary key of t1 (else, you need to enumerate the columns you want in both the select and group by clauses).

How to include o values results in COUNT? SQL Query

I need to count shutouts for goalies. I have two tables ("players" and "gamestats"). I have a problem getting the values when goalie has no "0" / zero values in "goalsagainst" column when the goalie is "dressed" (has games).
So, I need to count all the zero values from column "goalsagainst" when "dressed" column has a value 1 as a "shutout" column. And if values from column "goalsagains" are more than 0 "shutout" colmn values should be 0;
I have tried the other solutions from similar topics, but I always have the same outcome where only the zero values are counted and other values are not shown.
My structure:
players
|p_id|pos|
--------
| 1 | G |
--------
| 2 | D |
--------
| 3 | O |
--------
| 4 | G |
stats
|g_id|p_id|goalsagainst|dressed|
--------------------------------
| 1 | 1 | 2 | 1 |
--------------------------------
| 1 | 4 | 0 | 0 |
--------------------------------
| 1 | 3 | NULL | 1 |
--------------------------------
| 1 | 2 | NULL | 1 |
--------------------------------
| 2 | 1 | 0 | 0 |
--------------------------------
| 2 | 4 | 0 | 1 |
--------------------------------
| 2 | 3 | NULL | 1 |
--------------------------------
| 2 | 2 | NULL | 1 |
SELECT
stats.id,
COUNT(stats.goalsagainst) AS shutouts
FROM `stats`
RIGHT JOIN players
ON stats.id = players.id
WHERE goalsagainst = 0
AND players.pos = 'G'
AND stats.dressed = 1
GROUP BY stats.id;
my result is:
p_id|shutouts
-------------
4 | 1
when it should be:
p_id|shutouts
-------------
1 | 0
-------------
4 | 1
Your problem is that your conditions on the stats table in your WHERE clause effectively turn the RIGHT JOIN into an INNER JOIN. To work around this, move the conditions to the ON clause. Secondly, you need to use players.p_id in the SELECT and GROUP BY as stats.p_id may be NULL:
SELECT players.p_id,
COUNT(stats.goalsagainst) AS shutouts
FROM `stats`
RIGHT JOIN players ON stats.p_id = players.p_id AND stats.dressed = 1 AND stats.goalsagainst = 0
WHERE players.pos = 'G'
GROUP BY players.p_id;
Output:
p_id shutouts
1 0
4 1
Demo on dbfiddle

How to query using left join to get the result

I am working on two tables on mysql in which I am trying to get all rows from left table along with the columns in the second table which are matching with first table.
business
id | business_name
-------------------
1 |abc
2 |def
3 |ghi
4 |jkl
5 |mno
orders
business_id_fk | order_status | date
----------------------------------------
2 | PCK | 30-03-2017
3 | DEL | 30-03-2017
2 | DEL | 30-03-2017
2 | PCK | 30-03-2017
4 | PCK | 28-03-2017
3 | PCK | 29-03-2017
4 | DEL | 30-03-2017
I want all rows from business table and count of each order status for every business on 30-03-2017 from orders table sort by total.
result set is:
id | business_name | total(order_status) | count(PCK) | count(DEL)
----------------------------------------------------
2 | def | 3 | 2 | 1
3 | ghi | 1 | 0 | 1
4 | jkl | 1 | 0 | 1
1 | abc | 0 | 0 | 0
5 | mno | 0 | 0 | 0
Please help me in query to getting the above result.
You can use conditional aggregation on the join:
select b.id,
b.business_name,
count(o.order_status) as total_count,
coalesce(sum(o.order_status = 'PCK'), 0) as count_PCK,
coalesce(sum(o.order_status = 'DEL'), 0) as count_DEL
from business b
left join orders o on b.id = o.business_id_fk
and o.date = '2017-03-30'
group by b.id,
b.business_name;
I have assumed the datatype of date column on orders table as date (or atleast formatted string in the format YYYY-MM-DD).
Demo

right join query return non-matching values

I am trying to optimize a query and I have it down to something like this,
select a.* from
(select id, count(oid) as cnt from stuff1 s1 inner join stuff2 s2 on s1.id=s2.id group by id) as a
right join
(select id,'0' as cnt from stuff2) as b
on a.id = b.id
Basically the goal was to get the count for each oid, where those having 0 count are also included. I had a query previous to this that worked fine but it took 30 seconds to execute. I am looking to optimize the old query with this one, but I am getting NULL values from table b. I need the values from table b to show up with id and 0. Any help would be greatly appreciated.
An example of the data set could be,
Stuff1
| oid | id |
|---- |----|
| 1 | 1 |
| 2 | 1 |
| 3 | 2 |
| 4 | 3 |
Stuff2
| id |
|----|
| 1 |
| 2 |
| 3 |
| 4 |
| 5 |
| 6 |
| 7 |
the query should produce
| id | cnt |
|----|-----|
| 1 | 2 |
| 2 | 1 |
| 3 | 1 |
| 4 | 0 |
| 5 | 0 |
| 6 | 0 |
| 7 | 0 |
Your query is syntactically incorrect (oid may not be defined; id in the select is ambiguous). However, I suspect you want a simple left join:
select s2.id, count(s1.id) as cnt
from stuff2 s2 left join
stuff1 s1
on s1.id = s2.id
group by s2.id;

Select 1 record from first table if condition is true in second table (all refeance rows active = 0)

I have two tables.
I want to select 1 record from first table if
condition is true in second table (active = 0)
table Lead:
-------------
| id | name |
-------------
| 1 | abc1 |
| 2 | abc2 |
| 3 | abc3 |
| 4 | abc4 |
| 5 | abc5 |
-------------
table LeadsDetails:
-------------------------
| id | lead_id | active |
-------------------------
| 1 | 1 | 1 |
| 2 | 1 | 0 |
| 3 | 2 | 0 |
| 4 | 3 | 1 |
| 5 | 4 | 0 |
| 6 | 5 | 0 |
| 7 | 5 | 0 |
--------------------------
expected output:
--------------
| id | name |
--------------
| 2 | abc2 |
| 4 | abc4 |
| 5 | abc5 |
--------------
SELECT `Lead`.`id`, `Lead`.`name`, `Lead`.`unsubscribe`
FROM `leads` AS `Lead` inner JOIN `LeadsDetails` AS `LeadsDetails`
ON (`LeadsDetails`.`lead_id` = `Lead`.`id`)
WHERE `LeadsDetails`.`active` = 0
This should run faster than not exists because the subquery won't run for every row; in this case I'm counting the number of situations where the active field value on table leadsdetails is not 0, for the given ID, and showing only rows where that count is 0 (ie. for the given id the active field is ALWAYS 0)
select l.id, l.name
from lead l
join leadsdetails ld
on l.id = ld.lead_id
group by l.id, l.name
having sum(case when ld.active <> 0 then 1 else 0 end) = 0
Fiddle: http://www.sqlfiddle.com/#!2/00970/2/0
As you need to get the records only when active column doesn't have 1
use NOT EXISTS
SQL FIDDLE DEMO : http://www.sqlfiddle.com/#!2/00970/1
SELECT * FROM
Lead L
WHERE NOT EXISTS (
SELECT 1 FROM LeasdDetails LD
where L.id = LD.lead_id
AND LD.active =1
)
I think you can do what you want with an exists clause:
select l.*
from Lead l
where exists (select 1 from LeadsDetails ld where ld.lead_id = l.id and ld.active = 0)