Creating table using select statement from multiple tables - sql

I have this university task to create table using SELECT statement from multiple tables, but it's not as simple... here's basic info:
I'm using 2 tables -
CITY(city_ID, name);
PERSON(person_ID, name, surname, city_ID);
--city_ID is FK indicating in which city person was born.
Now my task is to create new table
STATISTICS(city_ID, city_name, number_of_births);
--number_of_births is basically a count of people born in each city
Problem is that I have to use only SELECT statement to do so.
I've tried something like this: (I'm well aware that this cannot possibly work but as to give you a better idea where I'm stuck)
CREATE TABLE Statistics AS
(SELECT city.city_ID, city.name as "city_name", number_of_births AS
(SELECT COUNT(*) FROM person WHERE person.city_id = city.city_id)
FROM city, person);

For SQL Server you can do SELECT * INTO. Something like this:
SELECT
*
INTO Statistics
FROM (
SELECT
city.city_ID,
city.name as "city_name",
(SELECT COUNT(*) FROM person WHERE person.city_id = city.city_id) as 'number_of_births'
FROM city
inner join person on city.city_id = person.city_id
) t1

(Posted on behalf of the question author).
Ok, this got really messy. Dave Zych's answer was correct when rewritten in Oracle dialect.
CREATE TABLE Statistics AS SELECT * FROM (
SELECT DISTINCT
city.city_ID,
city.name AS "City_name",
(SELECT COUNT(*) FROM person WHERE person.city_ID = city.city_ID) AS "number_of_births"
FROM city INNER JOIN person ON city.city_ID = person.city_ID);

Related

Querying SQL table a second time with info from the first

I am running a query against a PeopleSoft database, and am unsure whether it is possible to get information from the same table, based on the initial query, in a single call. For example, the table I am hitting returns EmployeeID, FullName, FirstName, LastName, Position_NBR, and ReportsTo. But the ReportsTo is in the form of the manager's Position_NBR (found in same table), and I would like to get it in the name format. I would like to do something like this, but not sure if it is possible:
SELECT Employee_ID, FullName, FirstName, LastName, Position_NBR
,(Select Name From Employee Where Position_NBR='12345') As Manager
From Employee
Where EmployeeID='8675309'
Is this even possible, or do I need to fully return the first piece before I can use the second?
Yes, you can refer to the first table and it's best to limit the result of the subquery to 1 result (just in case the employee has 2 o more managers)
SELECT Employee_ID, FullName, FirstName, LastName, Position_NBR
,(Select Top 1 E2.Name From Employee as E2 Where E2.Position_NBR=Employee.Position_NBR) As Manager
From Employee
Where EmployeeID='8675309'
(T-SQL Syntax)
You should be able to do this by linking fields.
Here are some examples using the Oracle Database:
e.g.
SELECT
table1.Employee_ID, table1.Name, table1.Boss_ID
,(select table2.name from Employee table2 where table1.Boss_ID = table2.Employee_ID) As Manager
From
Employee table1
Where
table1.Employee_ID='333'
/
Alternately, try a SQL JOIN.
SELECT
table1.Employee_ID, table1.Name, table1.Boss_ID
,table2.Name As Manager
From
Employee table1
inner join Employee table2
on table1.Boss_ID = table2.Employee_ID
Where
table1.Employee_ID='333'
/
Here is a link to a working example with some fake data:
http://sqlfiddle.com/#!4/210580/7

what is the proper union or sql construct to resolve these 2 datasets?

I have a table UserParent:
Id, FirstName, LastName
I have a table UserChild:
Id, ParentUserId (FK), ChildAttributeX
I have the following sample SQL:
SELECT Id, 0 ChildUserId, FirstName, LastName, NULL FROM UserParent
UNION
SELECT ParentUserId, Id, FirstName, LastName, ChildAttributeX FROM UserChild
Some Users may exist in both tables. All Users are stored with basic info in UserParent although some Users who have ChildAttributeX will have a FK ref to the UserParent in UserChild along with the ChildAttributeX in UserChild.
How can I resolve this as part of a UNION or some other SQL technique so all Users are included in the result set, without duplicate users?
I think this is what you are looking for. If all records must exist in parent table, this will return all records from parent, and any record that exist in child table, but only unique records (DISTINCT does that).
SELECT DISTINCT UP.ID, UP.FirstName, UP.LastName
FROM UserParent UP
LEFT OUTER JOIN UserChild UC ON UP.ID = UC.ParentUserID
If you are looking for all the records present in both table, you can try below query:
SELECT
coalesce(UP.Id,UC.ParentUserId),
0 ChildUserId,
(UP.FirstName,UC.FirstName),
(UP.LastName,UC.LastName),
NULL FROM
UserParent UP
FULL OUTER JOIN
UserChild UC
ON UC.ParentUserId = UP.ID

duplicate answers when predicate in more than one field SQL

I'm so new to this that even the answers on questions similar to my one really don't make any sense to me (I started SQL last week)
I'm trying to list addresses from Table 1 where there are multiple in each address with the same first and surnames (i.e. John Smith and John Smith). I have first names and surnames in separate fields.
I tried
SELECT *
FROM addresses
WHERE EXISTS (
SELECT individuals.FirstName
AND individuals.Surname
FROM individuals
WHERE addresses.AddressID = individuals.AddressID
GROUP BY addresses.StreetName
HAVING COUNT( * ) >1`
but this just gives me a list of every address that has more than one person in it..
Can anyone give me a (simpleish) answer that I might get my head around.
Thanks, Stacey
If you add
individuals.FirstName, individuals.Surname
after
GROUP BY addresses.StreetName
then that should do what you want.
SELECT addresses.*
FROM addresses
INNER JOIN
(
SELECT AddressID
FROM individuals
GROUP BY AddressID, FirstName, Surname
HAVING COUNT(*) > 1
) as tbl1
ON tbl1.AddressID = addresses.AddressID
How about:
SELECT
a.*
FROM
addresses a
JOIN
individuals i
ON a.AddressID = i.AddressID
GROUP BY
a.StreetName, i.FirstName, i.Surname
HAVING
COUNT(1) > 1

How to fix this simple SQL query?

I have a database with three tables:
user_table
country_table
city_table
I want to write ANSI SQL which will allow me to fetch all the user data (i.e. user details including the name of the country of the last school and the name of the city they live in now).
The problem I am having is that I have to use a self join, and I am getting slightly confused.
The schema is shown below:
CREATE TABLE user_table (id int, first_name varchar(16), last_school_country_id int, city_id int);
CREATE TABLE country_table (id int, name varchar(32));
CREATE TABLE city_table (id int, country_id int, name varchar(32));
This is the query I have come up with so far, but the results are wrong, and sometimes, the db engine (mySQL), asks me if I want to show all [HUGE NUMBER HERE] results - which makes me suspect that I am unintentionally creating a cartesian product somewhere.
Can someone explain what is wrong with this SQL statement, and what I need to do to fix it?
SELECT usr.id AS id, usr.first_name, ctry1.name as loc_country_name, ctry2.name as school_country_name, city.name as loc_city_name
FROM user_table usr, country_table ctry1, country_table ctry2, city_table city
WHERE usr.last_school_country_id=ctry2.id
AND usr.city_id=city.id
AND city.country_id=ctry1.id
AND ctry1.id=ctry2.id;
Try this. I wrote it using ANSI syntax for clarity. I assume that you may not always have usr.city_id or usr.last_school_country_id, so I used a left outer join meaning you will always get usr records back regardless.
I also removed and ctry1.id=ctry2.id, because that would require the user's current city to be in the same country as their last_school_country_id, which I don't think is always the case.
SELECT usr.id AS id, usr.first_name, ctry1.name as loc_country_name, ctry2.name as school_country_name, city.name as loc_city_name
FROM user_table usr
left outer join city_table city on usr.city_id=city.id
left outer join country_table ctry1 on city.country_id=ctry1.id
left outer join country_table ctry2 on usr.last_school_country_id=ctry2.id
This query selects all users whose city is in the same country as their last school:
SELECT usr.id AS id, usr.first_name, ctry1.name as loc_country_name, ctry2.name as school_country_name, city.name as loc_city_name
FROM user_table usr
JOIN city
ON city.id = usr.city_id
JOIN country_table ctry1
ON ctry1.id = city.country_id
JOIN country_table ctry2
ON ctry2.id = usr.last_school_country_id
WHERE ctry1.id = ctry2.id
It is synonymous to your original query.
As long as all fields named id are primary keys, this query cannot return more records than there are in user_table.
Make sure that all id are PRIMARY KEYs and you don't have duplicates.
Could you please run these queries:
SELECT COUNT(*)
FROM user_table
SELECT COUNT(*), COUNT(DISTINCT id)
FROM city
SELECT COUNT(*), COUNT(DISTINCT id)
FROM country_table
and post the output here?
normally if you're joining 3 tables there will be two joining statements. always 1 less then the number of items being joined.
Never mind, I understand why you might need the join,
going to keep working at the code.
SELECT user_table.*, contry_table.*, city_table.* FROM user_table, country_table, city_table WHERE country_table.id = last_school_country_id AND city_id = city_table.id

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'