Pretty basic SQL query involving count - mysql

Let's say I have the following schema
Company:
-> company_id
-> company_name
Building_to_company:
-> building_id
-> company_id
So each building has its own id as well as a company id which relates it to a single company.
the following query gives two columns -- one for the company name, and then its associated buildings.
SELECT company.company_name, building_to_company.building_id
FROM company, building_to_company
WHERE company.company_id = building_to_company.company_id;
The returned table would look something like this:
Company Name | Building Id
Smith Banking 2001
Smith Banking 0034
Smith Banking 0101
Smith Banking 4055
Reynolds 8191
TradeCo 7119
TradeCo 8510
So that's all simple enough.
But I need to do something a bit different. I need 2 columns. One for the company name and then on the right the number of buildings it owns. And then for a little extra challenge I only want to list companies with 3 or less buildings.
At this point the only real progress I've made is coming up with the query above. I know I some how have to use count on the building_id column and count the number of buildings associated with each company. And then at that point I can limit things by using something like WHERE x < 4

You've basically got it in words already. Assuming company_name is unique, all you have to add to your explanation to get it to work is a GROUP BY clause:
SELECT company.company_name, COUNT(building_to_company.building_id)
FROM company
INNER JOIN building_to_company
ON company.company_id = building_to_company.company_id
GROUP BY company.company_name
(SQL Fiddle demo of this query in action)
To limit it to companies with 3 or less buildings, the key is you have to use a HAVING clause and not WHERE. This is because you want to filter based on the results of an aggregate (COUNT); simply put, WHERE filters come before aggregation and HAVING come after:
SELECT company.company_name, COUNT(building_to_company.building_id)
FROM company
INNER JOIN building_to_company
ON company.company_id = building_to_company.company_id
GROUP BY company.company_name
HAVING COUNT(building_to_company.building_id) < 4
(SQL Fiddle demo of this query in action)

I think you want something like this
SELECT c.company_name, count(b.building_id)
FROM
company as c,
building_to_company as b
WHERE c.company_id = b.company_id
GROUP BY c.company_name;

Use the Below SQL-statement to find the company name with its own building count in descending order.
SELECT company.company_name, count(building_to_company.building_id)
FROM company (nolock), building_to_company(nolock)
WHERE company.company_id = building_to_company.company_id
group by company.company_name
having count(building_to_company.building_id)<=3
order by count(building_to_company.building_id) desc
Kindly let me know if you have any issue. Thanks

Related

SQL Select From Master - Detail Tables (Formatted Data)

I have two tables, named supplier and contacts.
The data in the contact table corresponds to a record on the supplier table.
Data of supplier
ID
Name
1
Hp
2
Huawei
Data for the contact
id
supplierId
Contact
1
1
John
2
1
Smith
3
1
Will
4
2
Doe
5
2
Wick
Now, I want to make a query that should return the following result
ID
Name
Contact
1
Hp
John, Smith, Will
2
Huawei
Doe, Wick
or should return the following result
ID
Name
Contact
Contact
Contact
1
Hp
John
Smith
Will
2
Huawei
Doe
Wick
You can use MySQL GROUP_CONCAT aggregation function to get your first output table. It's own ORDER BY clause will allow you to check the order of concatenation for the rows.
SELECT s.ID,
s.Name,
GROUP_CONCAT(c.Contact ORDER BY c.id)
FROM Supplier s
INNER JOIN Contact c
ON s.ID = c.supplierId
GROUP BY s.ID,
s.Name
You can use the window function ROW_NUMBER to assign a rank to each row inside the Contact table by partitioning on the supplier. Then split the contacts into three columns using an IF statement that will check for the three possible values of the ranking. The MAX aggregation function will allow you to remove the nulls.
SELECT s.ID,
s.Name,
MAX(IF(c.rn = 1, c.Contact, NULL)) AS Contact1,
MAX(IF(c.rn = 2, c.Contact, NULL)) AS Contact2,
MAX(IF(c.rn = 3, c.Contact, NULL)) AS Contact3
FROM Supplier s
INNER JOIN (SELECT *, ROW_NUMBER() OVER(PARTITION BY supplierId
ORDER BY id) AS rn
FROM Contact ) c
ON s.ID = c.supplierId
GROUP BY s.ID,
s.Name;
This second query may not work if you have more than three customers per supplier. In that case you either modify the query to contain the possible maximum amount of suppliers, or you use a prepared statement. If you really need such a solution, leave a comment below.
For a better understanding, you can play with these solutions here. The first solution will work on any MySQL version while the second one will work with MySQL 8.
Query to show the table like you want :
SELECT supplier.ID, supplier.Name, contact.Contact
FROM supplier
INNER JOIN contact
ON supplier.ID = contact.supplierId;

how to count number of customer referrals?

I have a table that looks like the following:
Cust_ID . Cust_name . Cust_referred_by
1 Allan 2
2 Blake 3
3 Jen 2
4 Zeke 1
In this scenario Allan was referred by Blake. How do I count how many referrals each customer has?
so far I have this code:
select cust_name, count(cust_referred_by)
from Customer
I believe I have to use self join table but not sure how to implement
Assuming you want to count the cust_reffered_by for each customer, then you can use the following query:
select cust_name, count(cust_reffered_by)
from Customer
group by cust_name
What I think you want to do, is to count the number of times a customer has been referred to. You can achieve that with the following query:
select cust_name, count(cust_id)
from Customer
group by cust_name
Without more information about the semantics of the table, it's hard to be sure what you're looking for though.
You can use group by and join to do it
select a.cust_name, count(b.Cust_ID)
from Customer a
join Customer b on a.Cust_ID=b.Cust_referred_by
group by a.cust_name
You can use this query to get sum of one column values:
$result=mysql_query("SELECT SUM(Cust_referred_by) AS total FROM Customer");
$row = mysql_fetch_array($result);
$sum = $row['total'];
echo $sum;
select
t.Cust_ID,
t.Cust_name,
(select count(s.Cust_ID) from Customer as s where s.Cust_referred_by = t.Cust_ID) as Referred
from Customer as t
You should use sub query for better versatility.
Using Group by is a very bad design, since you cannot group by two column at the same time.

SQL Query that fetches All the Names of the Mechanic that have all the skills in the skillsRequired table

I have a table Mechanic which has rows like
MechName Mechanic Skill
A Bike Repair
A Car Repair
B Bike Repair
B Car Repair
B Oil Change
C Oil Change
Another Table SkillsRequired
Skills
Bike Repair
Oil Change
Car Repair.
Need to Write a Query to Fetch all the Names of the Mechanic That have all the skills listed in the SkillsRequired Table.
ANS: Only B has to be in the result because only B has all the 3 skills required.
PS: Have an idea about a solution invloving groupby and counts but that may not be completely right.
Thanks #inquisitive_mind for the below Solution. But can we formulate this differently? I need another Query that does exactly what the below query does.
select MechName from Skills a join Mechanic b
on a.Skills = b.MechSkill
group by Mechname
having count(MechSkill) = (select count(*) from Skills)
select MechName from Skills a join Mechanic b
on a.Skills = b.MechSkill
group by Mechname
having count(MechSkill) = (select count(*) from Skills)
I am editing my response to allow you to search for a combination of items as well.
SELECT MechName, COUNT(DISTINCT Skill)
FROM Mechanic
WHERE Skill IN ('Oil Change', 'Car Repair', 'Bike Repair')
GROUP BY MechName
HAVING COUNT(DISTINCT Skill) = 3;

Marking Records as duplicates in mySQL

I am not a databases guy,but I have been given the "fun" job of cleaning up someone else's database. We have many duplicate record in our databases and some of customers are getting double or triple billed every month.
Given the following Database example
:
Table: Customers
ID Name Phone DoNotBill
1 Acme Inc 5125551212 No
2 ABC LLC 7138221661 No
3 Big Inc 4132229807 No
4 Acme 5125551212 No
5 Tree Top 2127657654 No
Is it possible to write a query that Identifies the all duplicate phone numbers (in this case records 1 and 4) and then marks and duplicate records yes by updating the DoNotBill column. But leaves the first record unmarked.
In this example case we would be left with:
ID Name Phone DoNotBill
1 Acme Inc 5125551212 No
2 ABC LLC 7138221661 No
3 Big Inc 4132229807 No
4 Acme 5125551212 Yes
5 Tree Top 2127657654 No
something like this?
UPDATE
customers cust,
(SELECT
c1.ID,
c1.name,
c1.phone,
c1.DoNotBill
FROM customers c
LEFT JOIN
(SELECT
cc.ID
FROM customers cc
) as c1 on c1.phone = c.phone
) dup
SET cust.DoNotBill = 'Yes' WHERE cust.id=dup.id ;
To begin with I assume that the DoNotBill column only has two possible values; yes and no. In that case it should be bool instead of varchar, meaning it would be either true or false.
Furthermore I don't get the meaning of the DoNotBill column. Why wouldn't you just use something like this?
select distinct phone from customers
SQL SELECT DISTINCT
That would give you the phone numbers without duplicates and without the need for an extra column.
This depends on ur data amount
You can do it in steps and make use some tools like excel...
This qrt
SELECT a.id,b.id,a.phone FROM clients a , clients b WHERE
A.phone =b.phone
And a.id!=b.id
The result is all duplicated records.
Add
Group by a.phone
And u will get 1 record for each 2 duplicates.
if you like the records and they are whT u need. ChNge select to select a.id and
Use this qry as subqry to an update sql statement
UPDATE clients SET billing='no' WHERE id IN ( sql goes here)
UPDATE customers c SET c.DoNotBill="Yes";
UPDATE customers c
JOIN (
SELECT MIN( ID ) ID, Phone
FROM customers
GROUP BY Phone
) u ON c.ID = u.ID AND c.Phone = u.Phone
SET c.DoNotBill="No";
That way not only duplicates are eliminated, but all multiple entries are dealt with.

mysql left join duplicates

ive been searching for hours but cant find a solution. its a bit complicated so i'll break it down into a very simple example
i have two tables; people and cars
people:
name_id firstname
1 john
2 tony
3 peter
4 henry
cars:
name_id car_name
1 vw gulf
1 ferrari
2 mustang
4 toyota
as can be seen, they are linked by name_id, and john has 2 cars, tony has 1, peter has 0 and henry has 1.
i simply want to do a single mysql search for who has a (1 or more) car. so the anwser should be john, tony, henry.
the people table is the master table, and im using LEFT JOIN to add the cars. my problem arises from the duplicates. the fact that the table im joining has 2 entries for 1 id in the master.
im playing around with DISTINCT and GROUP BY but i cant seem to get it to work.
any help is much appreciated.
EDIT: adding the query:
$query = "
SELECT profiles.*, invoices.paid, COUNT(*) as num
FROM profiles
LEFT JOIN invoices ON (profiles.id=invoices.profileid)
WHERE (profiles.id LIKE '%$id%')
GROUP BY invoices.profileid
";
try this
select distinct p.name_id, firstname
from people p, cars c
where p.name_id = c.name_id
or use joins
select distinct p.name_id, firstname
from people p
inner join cars c
on p.name_id = c.name_id
If you only want to show people that have a car, then you should use a RIGHT JOIN. This will stop any results from the left table (people) to be returned if they didn't have a match in the cars table.
Group by the persons name to remove duplicates.
SELECT firstname
FROM people P
RIGHT JOIN cars C ON C.name_id = P.name_id
GROUP BY firstname
SELECT DISTINCT firstname
FROM people
JOIN cars ON cars.name_id = people.name_id;
If this doesn't work you might have to show us the full problem.
The way to propose it there's no need for a left join since you need at least a car per person. Left join is implicitely an OUTER join and is intended to return the results with 0 corresponding records in the joinned table.