How to query using left join to get the result - mysql

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

Related

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

Count with LEFT JOIN shows only one row

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

How to achieve multiple row criteria in single table

mysql> select * from productdetails;
+----------+---------+--------+
| customer | product | is_use |
+----------+---------+--------+
| 1 | 1 | 0 |
| 1 | 2 | 0 |
| 1 | 3 | 1 |
| 2 | 1 | 1 |
| 2 | 2 | 0 |
| 2 | 3 | 1 |
| 3 | 1 | 1 |
| 3 | 2 | 1 |
| 3 | 3 | 1 |
| 4 | 1 | 0 |
| 4 | 2 | 1 |
| 4 | 3 | 1 |
+----------+---------+--------+
12 rows in set (0.00 sec)
How to get the customers for using both product 1 and 2 from the above table
In order to know which customers use both products, you'd aggreagte per customer:
select customer
from productdetails
group by customer
having sum(product = 1 and is_use = 1) > 0
and sum(product = 2 and is_use = 1) > 0
;
Solutions using IN(1,2) will find customers who use either product 1 or product 2 (or both).
If you want to find customers who use both product 1 and product 2, you need to test for both simultaneously.
But a WHERE clause naturally applies conditions in the context of only one row at a time.
So you need to get two rows onto one row somehow.
The best way to do this is with a self-join:
SELECT p1.customer
FROM product_detail AS p1
JOIN product_detail AS p2 ON p1.customer = p2.customer
WHERE p1.product = 1 AND p1.is_use = 1
AND p2.product = 2 AND p2.is_use = 1
You can use IN clause:
SELECT customer
FROM product_detail
WHERE product IN (1, 2)
AND is_use = 1;

MySQL Grouping Query

I have a number of tables in my database.
Table: ObjectToPerson
For example if I had a number of entries below in the database:
+----+------------+------------+----------+----------+--------------+
| Id | WeekNumber | Date | PersonId | ObjectId | ObjectTypeId |
+----+------------+------------+----------+----------+--------------+
| 1 | 1 | 2015-11-04 | 1 | 1 | 1 |
| 2 | 1 | 2015-11-04 | 1 | 3 | 2 |
| 3 | 1 | 2015-11-04 | 2 | 2 | 1 |
| 4 | 1 | 2015-11-04 | 2 | 4 | 2 |
+----+------------+------------+----------+----------+--------------+
I am wanting to return the results back as two lines as follows:
+------+------------+----------+----------------------------+----------------------------+
| Week | Date | PersonId | ObjectId(ObjectTypeId = 1) | ObjectId(ObjectTypeId = 2) |
+------+------------+----------+----------------------------+----------------------------+
| 1 | 2015-11-04 | 1 | 1 | 3 |
| 1 | 2015-11-04 | 2 | 2 | 4 |
+------+------------+----------+----------------------------+----------------------------+
I am thinking of some sort of Group By query but I just can't seem to get it right.
Select * From ObjectToPerson
Left Join Objects O On O.Id = ObjectToPerson.ObjectId And ObjectToPerson.ObjectTypeId = 1
Left Join Objects O On O.Id = ObjectToPerson.ObjectId And ObjectToPerson.ObjectTypeId = 2
Can someone explain how I would get to this please?
You could use CASE to only select the ObjectId if the type is correct for the column, then use MAX/GROUP BY to group the result into a single row per person/week/date.
SELECT WeekNumber week, date, personid,
MAX(CASE WHEN ObjectTypeId=1 THEN ObjectId END) Type1,
MAX(CASE WHEN ObjectTypeId=2 THEN ObjectId END) Type2
FROM ObjectToPerson
GROUP BY week, date, personid
An SQLfiddle to test with.
You don't want two joins, you want a WHERE clause;
SELECT * FROM ObjectToPerson
LEFT JOIN Objects O ON O.Id = ObjectToPerson.ObjectId
WHERE ObjectToPerson.ObjectTypeId IN(1,2)

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;