SQL Query with a subquery - sql

I need to retrieve the player number, name, street and town for all players that live in the same street and town as the players with number 6 or 7;
I am not sure how to write the SQL Query, i think i need to have a subquery in the WHERE clause but can't figure out how to do it.
This is what i came up with, but i have no way of testing it at this point
SELECT playerNo, name, street, town
FROM Players
WHERE street IN ( SELECT street, playerNo
FROM Players
WHERE playerNo IN (6,7));
AND town IN (SELECT town, playerNo
FROM Players
WHERE playerNo IN (6,7));
Should be compatible with Oracle 10g
Thanks to everyone who replied!

You didn't state your DBMS so this is the ANSI SQL solution (which works in Oracle, PostgreSQL, DB2, Teradata, MySQL and probably a lot of others as well):
SELECT playerNo, name, street, town
FROM Players
WHERE (street, town) IN (SELECT street, town
FROM Players
WHERE playerNo IN (6,7));
A side note regarding the IN operator:
your the expression town IN (SELECT town, playerNO ... is invalid because the subselect must the exact same number of columns as the left hand side of the IN operator. In your case you would have to write town IN (SELECT town FROM ...)

Something like this should do the trick:
select t.playerNumber, t.name, t.street, t.town
from tablename t
inner join (select street, town from tablename where playerNumber in (6,7)) aux on aux.street = t.street and aux.town = t.town

SELECT p1.playerNo, p1.name, p1.street, p1.town
FROM Players AS p1
INNER JOIN Players AS p2 ON p2.street = p1.street AND p2.town = p1.town
WHERE p2.playerNo IN (6,7)
It's often best to avoid subqueries because the database optimizer can't 'see inside the parens'.

Related

Which Join for SQL plus query

I have 4 tables, I would like to select one column from each table, but only if the department has both 'Mick' and 'Dave working in it (must have both names, not one or the other). But it does not seem to be working properly:
SELECT SCHOOL_NAME, TOWN, COUNTY
FROM STUDENTS
NATURAL JOIN SCHOOLS NATURAL JOIN TOWNS NATURAL JOIN
COUNTIES
WHERE FIRST_NAME IN ('Mick','Dave)
/
I'm going wrong somewhere (probably lots of places :( ). Any help would be great
Don't use NATURAL JOIN. It is an abomination, because it does not take properly declared foreign key relationships into account. It only looks at the names of columns. This can introduce really hard to find errors.
Second, what you want is aggregation:
select sc.SCHOOL_NAME, t.TOWN, c.COUNTY
from STUDENTS st join
SCHOOLS sc
on st.? = sc.? join
TOWNS t
on t.? = ? join
COUNTIES c
on c.? = t.?
where FIRST_NAME in ('Mick', 'Dave')
group by sc.SCHOOL_NAME, t.TOWN, c.COUNTY
having count(distinct st.first_name) = 2;
The ? are placeholders for table and column names. If you are learning SQL, it is all the more important that you understand how columns line up for joins in different tables.
A where clause can only check the values in a single row. There is a separate row for each student, so there is no way -- with just a where -- to find both students. That is where the aggregation comes in.
You need at least three Join conditions, and properly end the string Dave with quote :
SELECT SCHOOL_NAME, TOWN, COUNTY
FROM SCHOOLS h
JOIN TOWNS t ON (t.id=h.town_id)
JOIN COUNTIES c ON (t.county_id=c.id)
WHERE EXISTS ( SELECT school_id
FROM STUDENTS s
WHERE s.first_name in ('Mick','Dave')
AND school_id = h.id
GROUP BY school_id
HAVING count(1)>1
);
SQL Fiddle Demo
You can use an analytic function in a sub-query to count the students who have the name Mick or Dave for each school_id (assuming that is your identifier for a school):
SELECT SCHOOL_NAME, TOWN, COUNTY
FROM ( SELECT *
FROM (
SELECT d.*,
COUNT(
DISTINCT
CASE WHEN FIRST_NAME IN ( 'Mick', 'Dave' ) THEN FIRST_NAME END
) OVER( PARTITION BY school_id )
AS num_matched
FROM STUDENTS d
)
WHERE num_matched = 2
)
NATURAL JOIN SCHOOLS
NATURAL JOIN TOWNS
NATURAL JOIN COUNTIES;
SQLFiddle
You would also be better to use an INNER JOIN and explicitly specify the join condition rather than relying on NATURAL JOIN.

SQL: Filter out entries that appear more than once

I'm new to SQL and hope to find some help here.
English is not my native language so if something seems unclear feel free to ask!
Like the topic name implies I want to filter out entries (Strings) from a table that exist more than once.
My code looks like this:
SELECT DISTINCT characterid, firstname, lastname, courseid
FROM Teaches
NATURAL JOIN Character
GROUP BY characterid, firstname, lastname, courseid
And it gives me this:
Table
The task is to filter out everyone who teaches more than 1 course. In this case it would be Snape and Quirrell.
I tried it with counting
HAVING count(characterid) > 1
But that didn't work. I would be very happy if someone could help me and maybe explain why that count didn't work. Thank you in advance!
EDIT: If I say "filter" then I mean I want it as a result table. So that in the end I get a table with 2 rows with
1) characterid Severus Snape
2) characterid Quirinus Quirrell
Sorry for being so unclear. Also I only included the courseid in the SELECT statement to see who teaches more than one course more clearly. The final table should only have the three columns "characterid", "firstname" and "lastname"
EDIT2: Here is the structure of the data base. Maybe I'm completely wrong so it could be helpful to you guys: Structure
Why that count didn't work? Because you group courseid, so it only count for each courseid, not count all course for each characterid
SO you should change it to
SELECT
characterid, firstname, lastname
FROM
Teaches
NATURAL JOIN
Character
GROUP BY
characterid, firstname, lastname
HAVING
COUNT(*) > 1;
And I suggest you use INNER JOIN instead of NATURAL JOIN. NATURAL JOIN is not standard, not clean, invisible to coder (Others can't know you want to join which columns, so it's not readable)
And according to your comment, I assume that you want to get all character that teaches more than 1 course in any year, any position.
So for your case you should use (if you want to get in any school then delete t.schoolid in the subquery):
SELECT
characterid, firstname, lastname
FROM
(
SELECT DISTINCT
c.characterid, c.firstname, c.lastname, t.courseid, t.schoolid
FROM
Teaches t
INNER JOIN
Character c
ON
t.characterid = c.characterid
)
GROUP BY
characterid, firstname, lastname
HAVING
COUNT(*) > 1;

Select SQL with multiple tables in Access 2010

Two database tables:
Continent table with ContinentID and ContinentName columns
City table with CityID, CityName and ContinentName columns
Situation:
I want to combine the corresponding city to its continent. Like Europe (continent) has Denmark (country).
However, what's wrong with my SQL statement?
select
CountryID, CountryName
from
Country
where
Country.ContientID = Contient.ContientID;
You actually need to join the tables
select CountryID, CountryName
from Country
inner join Contient on Country.ContientID=Contient.ContientID
You were probably trying the old, legacy implicit join syntax which would work like this
select CountryID, CountryName
from Country, Contient
where Country.ContientID=Contient.ContientID
but you should not use that any more.

Having count in SELECT clause

Find the names of cities that hosts both SALES and TRANSPORT departments
For my oracle database have this table
i.) DEPTLOC
//DEPTLOC
CITY DNAME
---------------------
NEWYORK IT
NEWYORK COMPUTER
LONDON Science
LONDON SALES
LONDON TRANSPORT
For my SQL select statement
SELECT CITY FROM DEPTLOC
WHERE
DEPTLOC.DNAME='SALES' OR DEPTLOC.DNAME='TRANSPORT'
GROUP BY
CITY
HAVING COUNT(*)=2;
the output always display
no rows selected.
My output should be
DNAME
--------
LONDON
For things like this, I try to use a simple join to the same table. First, I would have an index on the table by (City, DName).. then
select
d.City
from
deptLoc d
JOIN deptLoc d2
on d.city = d2.city
AND d2.dname = 'TRANSPORT'
where
d.dname = 'SALES'
It may look strange, but think about it. The outer portion WHERE clause only cares about cities that have ONE of the qualifiers. Why even count cities that dont even have that. So, now the join. Since you know the first qualifier on SALES is covered, re-join to the dept loc table again, but on the same city name AND the second instance is ALSO that of your 'TRANSPORT' component. You will be surprised at how fast it would be, especially on a large dataset.
can you try this :
SELECT CITY FROM DEPTLOC
WHERE
trim(DEPTLOC.DNAME)='SALES' OR trim(DEPTLOC.DNAME)='TRANSPORT'
GROUP BY
CITY
HAVING COUNT(*)=2;
I think in your data you have some different chars like space or new lines
you can check it
i think this could be a better query.
SELECT CITY
FROM DEPTLOC
WHERE
DEPTLOC.DNAME in ('SALES','TRANSPORT')
GROUP BY CITY

SQL query or sub-query?

I've got a table of student information in MySQL that looks like this (simplified):
| age : int | city : text | name : text |
-----------------------------------------------------
| | | |
I wish to select all student names and ages within a given city, and also, per student, how many other students in his age group (that is, how many students share his age value).
I managed to do this with a sub-query; something like:
select
name,
age as a,
(select
count(age)
from
tbl_students
where
age == a)
from
tbl_students
where
city = 'ny'
But it seems a bit slow, and I'm no SQL-wiz, so I figure I'd ask if there's a smarter way of doing this. The table is indexed by age and city.
select
t1.name,
t1.age as a,
count(t2.age) NumberSameAge
from
tbl_students t1 inner join tbl_students t2
on t1.age=t2.age
where
city = 'ny'
group by t1.name, t1.age
not tested, but something like that. I.o.w. a groupby on a join. This sometimes can be faster as the query you're running is doing a nested subquery for every row returned, and the query I posted above (or at least, the structure with a join and a groupby) performs a query on the related students just once.
It might be easier to grab a sub-query that grabs everything at once (vs. 1000 rows where it runs the sub-query 1000 times).
SELECT Age, count(*) AS SameAge FROM tbl_students
Making the full query:
SELECT t.Name, t.Age, s.SameAge
FROM tbl_students t
INNER JOIN (
SELECT Age, count(*) AS SameAge FROM tbl_students
) AS s
ON (t.Age = s.Age) -- m:1
WHERE t.City = 'NY'