I have a project where I have to use nested select and operators like EXISTS, IN, ALL, ANY, to find the name of the owners who own more apartments.
I have the 2 tables owners and apartments
Owner
"ID" NUMBER(5,0),
"NAME" VARCHAR2(20),
"PHONE" NUMBER(10,0),
CONSTRAINT "PROPR" PRIMARY KEY ("ID")
USING INDEX ENABLE;
Apartment
"ID_AP" NUMBER(5,0),
"ADDRESS" VARCHAR2(35),
"SURFACE" NUMBER(10,0),
"ID" NUMBER(5,0),
CONSTRAINT "APART" PRIMARY KEY ("ID_AP")
USING INDEX ENABLE;
In order to find the owners who have more than one apartment, I wrote this
SELECT name, id, count(id)
from apartment join owner
using (id)
group by id, name
having count(id)>1
But how do I use nested Selects and one of the operators EXISTS, IN, ALL, ANY?
For example like this:
select * from owner where id IN (
SELECT id
from apartment
group by id
having count(id)>1)
I am not quite sure that the query you wrote is correct .
The correct query that you provided would count(id_ap) instead of count(id)
SELECT o.id, o.name, count(a.id_ap)
from apartment a
join owner o on o.id = a.id
group by o.id, o.name
having count(a.id_ap)>1
The same query using in clause, but without the number of apartments, you only know that it's 2 or more
select o.id, o.name
from owner o
where o.id in (select distinct(a.id) from apartment a
group by a.id having count(a.id_ap) > 1);
You are missing a foreign key constraint on apartment table referencing owner table as well.
WITH myView(name, id,appcount)
as
SELECT name, id, (select count(id) FROM apartment where id = ow.id)
FROM owner ow
SELECT * from myView
WHERE appcount > 2
Create a inline View using WITH and use to write a query. (select count(id) FROM apartment where id = ow.id) in select of outer query will calculate apartment count.
Related
I have the next schema:
the schema
I need to identify those car owners who are always serviced by the same mechanic and output the names of the mechanic and his regular customer.
I have tried this code, but it only gives me the combinations, how can I count this combinations and print the most frequent?
select cars_license_plate,mechanics_personnel_number,count(*) from orders where cars_license_plate in
(
select license_plate from cars where drivers_license_number in
(
select license_number from drivers where full_name in(select distinct full_name from drivers)
)
) group by cars_license_plate, mechanics_personnel_number
;
I got 4 tables, Email_Company_Contact_Ref table is the table which linked with Email, Company, and Contact.
**Email_Company_Contact_Ref**
id = primary key
email_id = reference to Email.`id`
ref_id = it can be Company.id / Contact.id
table = reference from which table name
I try to use left join to get my output, but I got duplicated result. If I try inner join, I will not get any result at all, it is because Company and Contact this two tables does not have any thing common.
This is the output I would like to complete.
I able to use UNION to get the output, but it not really effective. I am thinking it should be a way to get the output result.. Please help.
Thanks!
Here is my mysql answer, hope this can help
SELECT e.email, r.table, c1.name AS company_name, c2.name AS contact_name
FROM email_company_contact_ref r
JOIN email e ON e.id = r.email_id
LEFT JOIN company c1 ON (c1.id = r.ref_id AND r.table = 'company')
LEFT JOIN contact c2 ON (c2.id = r.ref_id AND r.table = 'contact')
GROUP BY r.table, e.email
I don't think it can be done without a UNION. Here's my suggestion.
SELECT email_address, eccr.table table, company_name, contact_name
FROM Email e, Email_Company_Contact_Ref eccr,
(SELECT "Company" table, id, company_name, NULL contact_name
FROM Company
UNION ALL
SELECT "Contact" table, id, NULL company_name, contact_name
FROM Contact) cc
WHERE e.id = eccr.email_id
AND eccr.table = cc.table
AND eccr.email_id = cc.id
I'm not getting the ref_id part... Is it a foreign key? Or is that the primary key for the Email_Company_Contact_Ref table?
I would think you'd want to put the reference for the Email table in the Company and Contact tables. If you need more than one emails for them, then you should create two join tables: Company_Email and Contact_Email. Your current design (with references to table names as values for a column) is bad SQL design -- just because things like RoR promote it, it won't get any better.
With proper design, the equivalent of that complicated query would look something like:
CREATE TABLE Company_Email (company_id integer, email_address varchar(100),
FOREIGN KEY company_id REFERENCES Company (id));
CREATE TABLE Contact_Email (contact_id integer, email_address varchar(100),
FOREIGN KEY contact_id REFERENCES Contact (id));
SELECT email_address, 'Company' AS kind, company_name AS name
FROM Company_Email ce JOIN Company c ON company_id = c.id
UNION
SELECT email_address, 'Contact', contact_name
FROM Contact_Email ce JOIN Contact c ON contact_id = c.id;
If you can't change it, you'll have to do the UNION along the lines Barmar explained it.
Or, you can do a SELECT DISTINCT to get rid of the duplicates from your left joined query.
I have 3 tables:
districts | id, zipcode, district
subscription | id, userid, status, level
profile | id, userid, zip
I am trying to count the amount of zip codes from active subscriptions and group them by district. ( I am using LEFT() so I can can include zips in the #####-#### format). The query works in 6.4 seconds locally, but on the server isn't outputting in a timely manner. What can I do to speed this up?
I have written:
SELECT COUNT( d.zipcode ) total, d.district
FROM districts AS d
JOIN profile AS p ON d.zipcode = LEFT(p.zip, 5)
JOIN subscriptions AS s ON s.userid = p.userid
WHERE s.status = 1
GROUP BY d.district
Thanks!
create an index on:
d.zipcode
p.zip
s.userid
p.userid
s.status
That's because you're using a function in your join. Therefore no index can be used. Why do you save zip in table profile? Save the districts.id in profile instead of zip, that would make sense.
EDIT: Actually you shouldn't do overindexing like Dweeves suggests. But you should add a foreign key to profile referencing districts.
ALTER TABLE profile ADD CONSTRAINT fk_zip_districts FOREIGN KEY (districtsId) REFERENCING districts(id);
assuming that you do like I said above.
profile | id, userId, districtsId
I have two tables that I am trying to query from, Enrollment and Course. In the course Table, there is just one entry for each course, but in the Enrollment table, there is an entry for each student that is enrolled in any course, so there may be 30 entries for one course. My task is to find The course that has the most enrollments, and print out that course name, as well as the number of enrollments for that course. Here is my query so far
select c.CourseCode ,(SELECT count( * ) FROM Enrollment WHERE CourseCode = c.CourseCode) as test from Course c ;
this gives me the results:
CS227 - 29
CS228 - 34
CS309 - 31
CS311 - 25
, ect, which is good, but NOW, how do I print out only the class that has the most enrollments(in this case, CS228). I have tried using the max(), but I can't get anything to work.
Here is the table structure
create table Course(
CourseCode char(50),
CourseName char(50),
PreReq char (6));
create table Enrollment (
CourseCode char(6) NOT NULL,
SectionNo int NOT NULL,
StudentID char(9) NOT NULL references Student,
Grade char(4) NOT NULL,
primary key (CourseCode,StudentID),
foreign key (CourseCode, SectionNo) references Offering);
Just take the top 1 after ordering by the count.
That is:
Select Top 1 A.CourseCode, Count(*) From Course A inner join Enrollment B on (A.CourseCode=B.CourseCode)
Group By A.CourseCode
Order By Count(*) DESC
Also - use an inner join as I've shown here rather than a subquery. I do tend to like SubQueries and this one will work but it is just not appropriate in this kind of query!
Based on your comment, I think the blow query is what you want, although it is untested and I am not entirely sure on the HAVING clause being valid. From the documentation on MySQL's page, it seems it should work.
SELECT A.CourseCode, COUNT(*) AS count FROM Course A
JOIN Enrollment B ON A.CourseCode = B.CourseCode
GROUP BY A.CourseCode
HAVING count = MAX(count)
As for performance, I cannot tell if it's a good idea to run a MAX on an aggregate function (probably not).
Otherwise, just use the other query to return the top X and simply run through comparing to the previous number.
SELECT
c.CourseCode,
c.CourseName,
COUNT(*) AS cnt
FROM
Course AS c
INNER JOIN
Enrollment AS e
ON c.CourseCode = e.CourseCode
GROUP BY
c.CourseCode
HAVING
COUNT(*) =
( SELECT
COUNT(*) AS cnt
FROM
Enrollment AS e
GROUP BY
e.CourseCode
ORDER BY
cnt DESC
LIMIT 1
)
There are 4 tables:
Books : id, name, author, ecc...
Category : id, name
Library : id, name, street, city, ecc..
bookcorr : book_id, category_id, library_id
Ids are all keys.
The query must show the categories with the numbers of books in a defined Library. for ex:
Library X:
Romantic (50)
Yellow (40)
Science (30)
This is my query:
SELECT category.id
, category.name
, count(*) AS tot
FROM bookcorr
JOIN category
ON category.id = bookcorr.category_id
WHERE bookcorr.library_id = 'x'
GROUP BY bookcorr.category_id
ORDER BY tot DESC
and it's still slow, is there a way to get results faster ?
What indices do you have on these tables? The query suggests that bookcorr should have an index on (category_id, library_id).
Your query doesn't make use of Books or Library...
Change the query so that it would group on the leading table's column to avoid Using temporary:
SELECT category.id, category.name, COUNT(*) AS tot
FROM category
JOIN bookcorr
ON bookcorr.category_id = category.id
WHERE bookcorr.library_id = 'x'
GROUP BY
category.id
ORDER BY
tot DESC
and make sure that you have an index on bookcorr (library_id, category_id)