How to count different rows and put them all in same table in SQL? - sql

I want to count how many people are applied for each category in my database and put all of those counts in one table. I don't have exact idea how should I do that. I've done it already like this but I want to have all in one query, and not to do it like this for each category.
select
count(cc.fk_id_candidates) as 'category A'
from candidate_category cc, candidate c, category cat
where c.id=cc.fk_id_candidates and cc.fk_id_category=cat.id and category.name='A';
From that code I get number of people applied for category A as an output, which is correct, but I just need the same info for other categories too. I tried with case but it's not working right.
Thank you.

You would typically add a group by clause on the category name and/or id:
select cat.category.name, count(*) cnt
from candidate_category cc
inner join candidate c on c.id = cc.fk_id_candidates and
inner join category cat on cc.fk_id_category = cat.id
group by cat.id, cat.category.name;
Note that I changed your query to use standard joins (with the on keyword) rather than implicit joins (with commas in the from clause and conditions in the where clause) - this old syntax should not be used in new code.

As i understand you have three tables:
- candidate_category cc,
- candidate c,
- category cat
Also, you have Created below relationship using the REFERENCES:
where c.id=cc.fk_id_candidates
and cc.fk_id_category=cat.id
and category.name='A;
Now, you must have all the three tables in one table already and you can view it by:
and this is very important step to find a common column where you can filter it and find the proper data you want.
Select *
from candidate_category cc,
candidate c,
category cat
where c.id=cc.fk_id_candidates
and cc.fk_id_category=cat.id

Related

How to select * from multiple tables in SQL when "self-joining"?

This query tries to get information about a company and its parent company:
select c.*, p.*
from companies c, companies p
where c.parent_id = p.id and c.name ilike '%google%'
but this seems to return data from the parent company (the one specified latter) only, and is missing the c.*.
Perhaps the reason is that because this is a self-join, the second one overrides the first ones?
I'm using this via the Sequal gem.
What you observe is not what Postgres does for this query. It returns all columns of the table companies twice, once for each instance, effectively duplicating column names, which can be a problem for some clients that would expect unique column names.
db<>fiddle here

How can I get an info from third table in SQL

I need an info from a table which I can't get directly. So in one table I have people's names in second names of categories and third is the middle one(which is between them) cause relation is many-many. Now I need info which people are in category 'A' for example. I tried like this, but it is not working.
select
p.name,p.surname
from people p, category c, category_people cp
where
p.ID=cp.fk_ID_people and c.name='a';
From that I get list of all people, which is incorrect.
Please help. I also think that my logic is not working right.
Thank you.
You need an extra condition, since it seems like the category_people is the table making the many-to-many connection possible.
So that table probably has a fk_ID_people and a fk_ID_category field and you would need to update your query to:
select
p.name,p.surname
from people p, category c, category_people cp
where
p.ID=cp.fk_ID_people
and c.ID = cp.fk_ID_category
and c.name='a';
For the best practices you should always join instead of using where condition.
select
p.name,
p.surname
from people p
join category_people cp
on p.ID = cp.fk_ID_people
join category c
on c.ID = cp.fk_ID_category
where
c.name='a';

SQL WHERE <from another table>

Say you have these tables:
PHARMACY(**___id_pharmacy___**, name, addr, tel)
PHARMACIST(**___Insurance_number___**, name, surname, qualification, **id_pharmacy**)
SELLS(**___id_pharmacy___**, **___name___**, price)
DRUG(**___Name___**, chem_formula, **id_druggistshop**)
DRUGGISTSHOP(**___id_druggistshop___**, name, address)
I think this will be more specific.
So, I'm trying to construct an SQL statement, in which I will fetch the data from id_pharmacy and name FROM PHARMACY, the insurance_number, name, and surname columns from PHARMACIST, for all the pharmacies that sell the drug called Kronol.
And that's basically it. I know I'm missing the relationships in the code I wrote previously.
Note: Those column names which have underscores left and right to them are underlined(Primary keys).
The query you've written won't work in any DBMS that I know of.
You'll most likely want to use some combination of JOINs.
Since the exact schema isn't provided, consider this pseudo code, but hopefully it will get you on the right track.
SELECT PH.Ph_Number, PH.Name, PHCL.Ins_Number, PHCL.Name, PHCL.Surname
FROM PH
INNER JOIN PHCL ON PHCL.PH_Number = PH.Ph_Number
INNER JOIN MLIST ON MLIST.PH_Number = PH.PH_Number
WHERE MLIST.Name = "Andy"
I've obviously assumed some relationships between tables that may or may not exist, but hopefully this will be pretty close. The UNION operator won't work because you're selecting different columns and a different number of columns from the various tables. This is the wrong approach all together for what you're trying to do. It's also worth mentioning that a LEFT JOIN may or may not be a better option for you, depending on the exact requirements you're trying to meet.
Ok, try this query:
SELECT A.id_pharmacy, A.name AS PharmacyName, B.Insurance_number,
B.name AS PharmacistName, B.surname AS PharmacistSurname
FROM PHARMACY A
LEFT JOIN PHARMACIST B
ON A.id_pharmacy = B.id_pharmacy
WHERE A.id_pharmacy IN (SELECT id_pharmacy FROM SELLS WHERE name = 'Kronol')

SQL Counting and Joining

I'm taking a database course this semester, and we're learning SQL. I understand most simple queries, but I'm having some difficulty using the count aggregate function.
I'm supposed to relate an advertisement number to a property number to a branch number so that I can tally up the amount of advertisements by branch number and compute their cost. I set up what I think are two appropriate new views, but I'm clueless as to what to write for the select statement. Am I approaching this the correct way? I have a feeling I'm over complicating this bigtime...
with ad_prop(ad_no, property_no, overseen_by) as
(select a.ad_no, a.property_no, p.overseen_by
from advertisement as a, property as p
where a.property_no = p.property_no)
with prop_branch(property_no, overseen_by, allocated_to) as
(select p.property_no, p.overseen_by, s.allocated_to
from property as p, staff as s
where p.overseen_by = s.staff_no)
select distinct pb.allocated_to as branch_no, count( ??? ) * 100 as ad_cost
from prop_branch as pb, ad_prop as ap
where ap.property_no = pb.property_no
group by branch_no;
Any insight would be greatly appreciated!
You could simplify it like this:
advertisement
- ad_no
- property_no
property
- property_no
- overseen_by
staff
- staff_no
- allocated_to
SELECT s.allocated_to AS branch, COUNT(*) as num_ads, COUNT(*)*100 as ad_cost
FROM advertisement AS a
INNER JOIN property AS p ON a.property_no = p.property_no
INNER JOIN staff AS s ON p.overseen_by = s.staff_no
GROUP BY s.allocated_to;
Update: changed above to match your schema needs
You can condense your WITH clauses into a single statement. Then, the piece I think you are missing is that columns referenced in the column definition have to be aggregated if they aren't included in the GROUP BY clause. So you GROUP BY your distinct column then apply your aggregation and math in your column definitions.
SELECT
s.allocated_to AS branch_no
,COUNT(a.ad_no) AS ad_count
,(ad_count * 100) AS ad_cost
...
GROUP BY s.allocated_to
i can tell you that you are making it way too complicated. It should be a select statement with a couple of joins. You should re-read the chapter on joins or take a look at the following link
http://www.sql-tutorial.net/SQL-JOIN.asp
A join allows you to "combine" the data from two tables based on a common key between the two tables (you can chain more tables together with more joins). Once you have this "joined" table, you can pretend that it is really one table (aliases are used to indicate where that column came from). You understand how aggregates work on a single table right?
I'd prefer not to give you the answer so that you can actually learn :)

Select based on the number of appearances of an id in another table

I have a table B with cids and cities. I also have a table C that has these cids with extra information. I want to list all the cids in table C that are associated with ALL appearances of a given city in Table B.
My current solution relies on counting the number of times the given city appears in Table B and selecting only the cids that appear that many times. I don't know all the SQL syntax yet, but is there a way to select for this kind of pattern?
My current solution:
SELECT Agents.aid
FROM Agents, Customers, Orders
WHERE (Customers.city='Duluth')
AND (Agents.aid = Orders.aid)
AND (Customers.cid = Orders.cid)
GROUP BY Agents.aid
HAVING count(Agents.aid) > 1
It only works because I know right now with the HAVING statement.
Thanks for the help. I wasn't sure how to google this problem, since it's pretty specific.
EDIT: I'm pinpointing my problem a bit. I need to know how to determine if EVERY row in a table has a certain value for a field. Declaring a variable and counting the rows in a sub-selection and filtering out my results by IDs that appear that many times works, but It's really ugly.
There HAS to be a way to do this without explicitly count()ing rows. I hope.
Not an answer to your question, but a general improvement.
I'd recommend using JOIN syntax to join your tables together.
This would change your query to be:
SELECT Agents.aid
FROM Agents
INNER JOIN Orders
ON Agents.aid = Orders.aid
INNER JOIN Customers
ON Customers.cid = Orders.cid
WHERE Customers.city='Duluth'
GROUP BY Agents.aid
HAVING count(Agents.aid) > 1
What variant of SQL are you using?
To start with, you can (and should) use JOIN instead of doing it in the WHERE clause, e.g.,
select Agents.aid
from Agents
join Orders on Agents.aid = Orders.aid
join Customers on Customers.cid = Orders.cid
where Customers.city = 'Duluth'
group by Agents.aid
having count(Agents.aid) > 1
After that, I'm afraid I might be a little lost. Using the table names in your example query, what (in English, not pseudocode) are you trying to retrieve? For example, I think your sample query is retrieving the PK for all Agents that have been involved in at least 2 Orders involving Customers in Duluth.
Also, some table definitions for Agents, Orders, and Customers might help (then again, they might be irrelevant).
I'm not sure if I understood you problem, but I think the following query is what you want:
SELECT *
FROM customers b
INNER JOIN orders c USING (cid)
WHERE b.city = 'Duluth'
AND NOT EXISTS (SELECT 1
FROM customers b2
WHERE b2.city = b.city
AND b2.cid <> cid);
Probably you will need some indexes on these columns.