getting count on same column using inner join - mysql

I have a table like this, in which I need to set the male and female counts for the primary key id:
summaryTable:
id femaleCount maleCount
-----------------------------
s1 ? ?
s2 ? ?
... and so on
There is a detail table as below, that has the users corresponding to each id of summaryTable:
id parentId userId
--------------------------
1 s1 u1
2 s1 u2
3 s2 u2
4 s2 u2
...and so on
The third is the user table like this:
userTable:
userId gender
-------------
u1 M
u2 F
u3 F
..and so on
I have to update the summary table with the counts of male and female. So as per the above, for id=s1, femaleCount should be set to 1 , maleCOunt=1
For id=s2, femaleCOunt should get set to 2 and maleCount=0
Is this possible to do using an UPDATE query in MySQL?
I tried the following, but this returns the sum of occurences of a user i.e. if u1 occurs 2 times for p1(say), then it will return count as 2 and not 1:
SELECT
d.parentId,
SUM(gender = 'F') AS 'F#',
sum(gender = 'M') as 'M#'
FROM detailsTable as d
JOIN userTable as c on c.userId = d.userId
GROUP BY d.parentId;
Also tried as below, but it gave an error:
select d.parentId,
count(case when c.gender='M' then 1 end) as male_cnt,
count(case when c.gender='F' then 1 end) as female_cnt,
from detailsTable d, userTable c where d.userId=c.userId group by d.parentId, d.userId ;
Further, my problem doesnt just end at the select, I need to get the values and then update these in the summary table too.

I might be rusty on the syntax for MySql but I believe this does what you need. The CASE/SUM is effectively a pivot to get the counts, then you can update the table as normal.
UPDATE summaryTable AS st
INNER JOIN ( SELECT parentId
,SUM(CASE WHEN gender = 'f' THEN 1
ELSE 0
END) femaleCount
,SUM(CASE WHEN gender = 'm' THEN 1
ELSE 0
END) maleCount
FROM userTable d
INNER JOIN (SELECT DISTINCT parentId, userId FROM detail) ut ON d.userId = ut.userId
GROUP BY parentId
) AS c ON c.parentId = st.parentId
SET femaleCount = c.femaleCount
,maleCount = c.maleCount

Related

COnditional JOIN query in MySQL

I have two mysql tables
user:
|--------------------------------|
| id | name | type | ruser_type |
|--------------------------------|
| 1 | Admin | a | |
| 2 | | r | c |
|--------------------------------|
customer
|-------------------------|
| id | name | user_id |
|-------------------------|
| 1 | Sam | 2 |
|-------------------------|
If user.type is 'a' or 's', then its admin user whose name is in user table.
If user.type is 'r' and ruser_type is 'c', then its regular user which has a relation in customer table where customer.user_id = user.id
I want a query which would run a conditional join.
If user.type is 'a' or 's', then name would be fetched from user table.
If user.type is 'r' and and ruser_type is 'c', then name would be fetched from customer table with the JOIN condition customer.user_id = user.id.
For this, I have written a query like this:-
SELECT users.fname as adminFname, customers.fname as customerFname, users.type FROM users
LEFT JOIN customers ON (customers.user_id = users.id AND
(
(users.type = 'r' AND users.ruser_type = 'c')
OR users.type = 'a'
OR users.type = 's'
)
)
WHERE users.id = 1
Is there any possibility to optimize the query more?
Also, how can I write this query using Laravel eloquent?
FWIW, I find this marginally easier to read...
SELECT u.fname adminFname
, c.fname customerFname
, u.type
FROM users u
LEFT
JOIN customers c
ON c.user_id = u.id
WHERE u.id = 1
AND (
(u.type = 'r' AND u.ruser_type = 'c')
OR (u.type IN('a','s'))
)
I have written two sql query hope this will help you
SELECT CASE CU.type WHEN 'a' OR 's' THEN CU.name END AS name,
CASE WHEN CU.type = 'r' AND CU.ruser_type = 'c' THEN CR.name END AS cust_name, CU.type
FROM
user AS CU
LEFT JOIN customer AS CR ON CR.user_id = CU.id
In this you'll get result like this,
name cust_name type
Sam r
Admin a
and i have wrote another query like this,
SELECT CASE WHEN CU.type = 'a' OR 's' THEN CU.name ELSE CR.name END AS name, CU.type
FROM
user AS CU
LEFT JOIN customer AS CR ON CR.user_id = CU.id
In this you'll get result like this
name type
Sam r
Admin a
DB File Link
https://dbfiddle.uk/?rdbms=mysql_5.7&fiddle=b02d931b68a4f70d8b4a84144c60a572
This will give you required result for all users:
SELECT u.fname adminFname
, c.fname customerFname
, u.type
FROM users u
LEFT JOIN customers c
ON (u.type = 'r' AND u.ruser_type = 'c' AND c.user_id = u.id)
Add where condition as required.
You can even simplify it further to get common firstName column in output:
SELECT COALESCE(u.fname, c.fname) firstName, u.type
FROM users u
LEFT JOIN customers c
ON (u.type = 'r' AND u.ruser_type = 'c' AND c.user_id = u.id)

How to find the shops whose customers are only men?

I have this schema:
PERSON(Name, Sex)
FREQUENTS(Name, Shop)
My question is, how do I find the shops whose clients are exclusively men?
You can use the following using a GROUP BY with HAVING:
SELECT frequents.shop
FROM frequents LEFT JOIN person ON frequents.name = person.name
GROUP BY frequents.shop
HAVING SUM(person.sex = 'female') = 0 AND SUM(person.sex = 'male') > 0
demo at dbfiddle.uk
select shop
from
(select shop , (case when sex = 'Male' then 1 else 2 end)s_cnt
from frequents a11
join person a12
on a11.name = a12.name
group by shop , (case when sex = 'Male' then 1 else 2 end)
) a11
group by shop
having sum(s_cnt) = 1
For example NOT EXISTS
select distinct shop
from frequents
where not exists (
select 1
from person
where person.name = frequents.name and person.sex = 'female'
)
However, according to this test is may be better to use IS NULL approach:
select distinct shop
from frequents
left join person on person.name = frequents.name and person.sex = 'female'
where person.name is null
If you want exclusively men, then I would think:
SELECT f.shop
FROM frequents f JOIN
person p
ON f.name = p.name
GROUP BY f.shop
HAVING MIN(p.sex) = MAX(p.sex) AND -- all sex values are the same or NULL
COUNT(p.sex) = COUNT(*) AND -- no NULL values
MIN(p.sex) = 'male' -- the value is male
This version does not assume that there are only two genders.

MySql query on 3 different tables

I have 3 tables.
Owners:
ownerID name
1 josh
Pets:
petID name
1 M
2 x
3 f
4 h
PetsOwners:
petID ownerID
1 1
3 1
4 1
I have a query that returns the ownerID from a person. "SELECT ownerID FROM Owners WHERE name = 'josh';" This will return ownerID = 1. I need a query that returns all pets that josh owns. In this case will be "m", "f" and "h" according to the petsOwners table.
If you have ownerId use
SELECT p.name
FROM Pets p
JOIN PetsOwners po
ON p.petID = po.petID
WHERE po.ownerID = 1
If you only have the owner name, need join all 3 tables
SELECT p.name
FROM Pets p
JOIN PetsOwners po
ON p.petID = po.petID
JOIN Owners o
ON po.ownerID = o.ownerID
WHERE o.name = 'josh'
If you just want their names:
SELECT Pets.name
FROM Pets, PetsOwners, Owners
WHERE Pets.petID = PetsOwners.petID
AND Owners.ownerID = PetsOwners.ownerID;
try this:
select a.ownerID,a.`name`as OwnerName, b.petID,b.`name` as PetName from
(select ownerID `name` from Owners) as a
right join
(select a.petID,a.`name`,OwnerID from
(select petID,`name` from Pets) as a
left JOIN
(select petID,OwnerID from PetsOwners) as b
on a.petID = b.petID) as b
on a.ownerID = b.OwnerID
I see your question and this is easy you see the query I wrote blow:
SELECT links.`link`,
links.`link_id`
FROM links
WHERE links.`link_id` NOT IN
(SELECT Y.`link_id`
FROM users X
INNER JOIN user_visited Y ON X.`user_id` = Y.`user_id`
WHERE X.`user_id` = 22 );

MySQL Select Distinct with Left Join?

I am trying to get a list of company_id's that have no company-level notes. The company may, however, have location-level notes.
company
-------------------------
company_id name deleted
1 Foo 0
2 Bar 0
3 Baz 0
location
-----------------------
location_id company_id
6 1
7 2
8 3
note
-----------------------------------------
note_id company_id location_id deleted
10 2 6 0 // location-level note
11 1 7 0 // location-level note
12 null 8 0 // location-level note
13 2 null 0 // company-level note
I would want my result table to be this:
company_id name
1 Foo
3 Baz
Update
Foo/company_id = 1 does not have a company-level note because the note also has a location_id, which makes it a location-level note. Company-level notes are notes that only link to a company (and not a location).
End of Update
I've tried doing something like this, but it returns an empty set, so I'm not sure if it's working and there aren't any companies without company-level notes or if I'm doing something wrong.
SELECT DISTINCT
c.company_id,
c.name
FROM company AS c
LEFT JOIN note AS n
ON c.company_id = n.company_id
WHERE
c.deleted = 0 AND
n.deleted = 0 AND
n.location_id IS NOT NULL AND
n.location_id != 0 AND
c.company_id = (SELECT MAX(company_id) FROM company)
Revised Accepted Answer by Mike
SELECT
company_id,
name
FROM company
WHERE
deleted = 0 AND
company_id NOT IN (
SELECT DISTINCT
c.company_id
FROM company AS c
INNER JOIN note AS n
ON c.company_id = n.company_id
WHERE (
n.deleted = 0 AND
(n.location_id IS NULL OR
n.location_id = 0)
)
);
The easiest way to think about this is to first find the all the companies that have company level notes, which you can do with
select distinct c.company_id
from company c
inner join notes n
on c.company_id = n.company_id
where n.location_id is null;
Then simply remove these companies from the company select:
select company_id,
name
from company
where company_id not in (select distinct c.company_id
from company c
inner join notes n
on c.company_id = n.company_id
where n.location_id is null);
*Updated to use inner join instead of comma-separated join.
SELECT DISTINCT c.*
FROM company c
LEFT
JOIN note n
ON n.company_id = c.company_id
AND n.location_id IS NULL
WHERE n.note_id IS NULL;

MYSQL - Union SELECT & GROUP BY Not working

I have 3 table, log, member, also guest, but my log i stored as customer(user)'s id only, which is either their guest_id or member_id. So here's the problem, because they're from different table, I'm not sure how to join & group together their data.
checkout_log table
id user_id checkout_as
--------------------------------------
1 1 member
2 2 guest
members table
id fullname
--------------------------------------
1 member01
2 member02
guests table
id fullname
--------------------------------------
1 guest01
2 guest02
What I wanted to Achieve - Result
id user_id fullname checkout_as
----------------------------------------------
1 1 member01 member
2 2 guest02 guest
Had tried following sql statement with UNION ALL, or GROUP BY , but had no luck.
SELECT * FROM
(
SELECT checkout_log.id,checkout_log.user_id,guests.fullname,guests.email,checkout_log.checkout_as
FROM checkout_log
LEFT JOIN checkout_product ON checkout_product.checkout_log_id = checkout_log.id
LEFT JOIN guests ON checkout_log.user_id = guests.id
UNION ALL
SELECT checkout_log.id,checkout_log.user_id,members.fullname,members.email,checkout_log.checkout_as
FROM checkout_log
LEFT JOIN checkout_product ON checkout_product.checkout_log_id = checkout_log.id
LEFT JOIN members ON checkout_log.user_id = members.id
) derivedTable
GROUP BY id
Try doing this with joins instead of union
select cl.id, cl.user_id,
coalesce(m.fullname, g.fullname) as fullname,
cl.checkout_as
from checkout_log cl left join
members m
on cl.user_id = m.id and cl.checkout_as = 'member' left join
guests g
on cl.user_id = g.id and cl.checkout_as = 'guest';