SQL subqueries - which order do you perform the SELECT statements? - sql

I just started learning SQL a couple of days ago, and I'm trying to understand which order I should use the SELECT statement when building subqueries. Here is a simple example of what I am trying to accomplish.
I have two tables - One that specifies the demographics of a customer list, and the other that details how they heard about our company.
In the first table, my customers are listed as either Male or Female in the Gender column, and then in the next column, their ethnicity is specified (Caucasian, African American, Hispanic, etc).
In the second table, there is a Referral column that specifies how they heard about our company (TV, radio, website, etc).
I want to first filter the customers by gender (I want to show only Female data), and then I want to count how many times our customers found us through our website for each ethnicity listed in the table.
SELECT Ethnicity, COUNT(Referral)
FROM Demographics, Marketing
WHERE Demographics.id = Marketing.source_id
AND Referral = 'website'
/* confused about how to put subquery here saying Gender = 'Female' */
ORDER BY Ethnicity
Basically, I'm confused about how to properly include the subquery and if I am even filtering in the correct order.
But here is what I want my table to look like:
/*Data is shown for ONLY Females */
Referral Caucasian African American Hispanic Asian
website 7 19 14 22
I'm sorry, this code is probably really messed up. Please help if you can.

From what you've described, you don't need a subquery:
SELECT Ethnicity, COUNT(Referral)
FROM Demographics, Marketing
WHERE Demographics.id = Marketing.source_id
AND Referral = 'website'
AND Gender = 'Female'
ORDER BY Ethnicity
...note that this gives you a different resultset from the one you've shown, though, with ethnicity, count on each row.

When you are using two table u must use the INNER JOIN syntax:
http://w3schools.com/sql/sql_join_inner.asp
SELECT Ethnicity, COUNT(Referral)
FROM Demographics INNER JOIN Marketing
...
AND Referral = 'website'
AND Gender = 'Female'
...

Related

Why use many columns in GROUP BY and HAVING clause in these examples

Given the schema here I'm trying to understand and solve the below 3 sql queries as I'm confused:
1- Present a table giving the names of the countries with ≥ 50% urbanization
rates, their urbanization rates, and their per capita GDP. Note that
urbanization rate is the percentage of population living in cities. Do not
count cities with NULL values for population.
SELECT country.name, round(sum(city.population)/country.population, 3) AS urban, round(gdp/country.population, 3) AS gdppc
FROM city
INNER JOIN country ON code = country
INNER JOIN economy ON code = economy.country
WHERE city.population IS NOT NULL
GROUP BY country.name, country.population, economy.gdp
HAVING round(sum(city.population)/country.population, 3) >= 0.5
ORDER BY urban DESC;
In the above query, Why I need to include country.population and economy.gdp in the GROUP BY? If I tried using just country.name in the GROUP BY I get an error saying I should include the others.
2- Show organizations that have as members all the European countries with over 50 million people?
SELECT name
FROM organization
INNER JOIN (SELECT organization
FROM country
INNER JOIN encompasses
ON code = encompasses.country
INNER JOIN ismember
ON code = ismember.country
WHERE population > 50000000 AND continent = 'Europe'
GROUP BY organization
HAVING count(ismember.country) = (SELECT count(*)
FROM country
INNER JOIN encompasses
ON code = country
WHERE population > 50000000 AND continent = 'Europe'))
AS innerQuery
ON abbreviation = innerQuery.organization;
Why I need the HAVING Part above?
3- Insert a new organization called “Tivoli” and a trigger that says if Germany joins “Tivoli” then so too must the UK and France. Insert Germany into the “Tivoli” organization. Confirm proper behavior.
I tried the below script but it's not working, any advice please?
do $$
begin
IF(NOT EXISTS ( SELECT 1 FROM organization WHERE organization."name" = 'Tivoli' AND organization.country = 'D' ))
BEGIN
INSERT INTO organization VALUES ('Tivoli','Tivoli organization',NULL,'F',NULL,NULL);
INSERT INTO organization VALUES ('Tivoli','Tivoli organization',NULL,'GB',NULL,NULL);
END;
end $$
1)
You used country.population and economy.gdp in the select, outside of aggregate functions ( COUNT(), AVG() and SUM() ), and you have a GROUP BY. Everything that you select has to be in GROUP BY or inside of aggregate functions.
2)
Because you were asked to show organizations that have ALL of 50mil + people countries. With HAVING, you check if that organization has the right amount of countries.
3)
organization."name" = 'Tivoli'
It's supposed to be :
organization.name
First of all, you should limit a question to one only, not 3. But here are some pointers for all 3:
In the above query, Why I need to include country.population and economy.gdp in the GROUP BY? If I tried using just country.name in the GROUP BY I get an error saying I should include the others.
This is a requirement. A group by country.name alone would work (in Postgres 9.1+) only if the other two fields are known to be functionally dependent on country.name. But probably country.name is not the primary key of the country table, so in theory it is possible to have two records in that table with the same name, but different population.
The rule is as follows:
When GROUP BY is present, it is not valid for the SELECT list expressions to refer to ungrouped columns except within aggregate functions or if the ungrouped column is functionally dependent on the grouped columns, since there would otherwise be more than one possible value to return for an ungrouped column. A functional dependency exists if the grouped columns (or a subset thereof) are the primary key of the table containing the ungrouped column.
This is implemented since version 9.1.
Why I need the HAVING Part above?
Because a condition on an aggregate (count in this case) can only be performed after grouping, and can thus not be expressed in the where clause. In this case the having clause makes sure that the organisation is not only present in some big EU Member States, but all big EU Member states.
I tried the below script but it's not working, any advice please?
Without a proper database schema, it is not possible to provide you with the correct SQ, but from the ERD diagram it seems that the organization table does not have a country field. Instead the ismember table connects organizations with countries. You would only insert one organization, but several ismember records (one per Member State involved)
It is better also to name the fields in your insert statement, so it is clear which value corresponds to which field.

SQL: A Count that merges/joins two columns

A company wants to know what has happened since the beginning of 1999 on hiring. The human resources manager has asked you to
produce a count of the employees hired since then, broken down by both age and gender simultaneously (i.e. 17 males, 25 females, etc.). Write a query that does that.
This is what I have so far. I couldn't figure out how to merge two columns simultaneously. Any thoughts?
SELECT EmployeeID, COUNT(*) AS "Number of employees"
FROM Employee
WHERE Age and Gender
GROUP BY EmployeeID
HAVING COUNT(*) BEGIN = 1999
I am not pretty much sure about your requirement but the right way to write a query is as following and this may fulfill your requirement with slight changes...
SELECT Gender, COUNT(*) AS "Number of employees", Age
FROM Employee
WHERE year(column_name) >= 1999 --Give a real date column here
GROUP BY Age, Gender
Please provide table structure and complete desired output for the exact answer.

Inner join (or intersect) over three tables

I have a database with three tables named: NameAddressPhone, NameAddressAge, and AgeSex.
Table NameAddressPhone has columns name, address, and phone.
Table NameAddressAge has columns name, address, and age.
Table AgeSex has columns age and sex.
I'm trying to write a (SQLite) query to find the names, addresses, and ages such that the names and addresses appear in both NameAddressPhone and NameAddressAge, and such that the ages appear in both NameAddressAgeand AgeSex. I'm able to get halfway there (i.e., with two tables) using inner join, but I only dabble in SQL and would appreciate some help from an expert in getting this right. I have seen solutions that appear to be similar, but don't quite follow their logic.
Thanks in advance.
Chris
I think you just want to join these together on their obvious keys:
select *
from NameAddressPhone nap join
NameAddressAge naa
on nap.name = naa.name and
nap.address = naa.address join
(select distinct age
from AgeSex asx
) asx
on asx.age = naa.age
This is selecting the distinct ages in the AgeSex to prevent the proliferation of rows. Presumably, one age could appear multiple times in that table, which would result in duplicate rows on output.
I am assuming your tables have the following layout
NameAddressPhone
================
Name
Address
Phone
NameAddressAge
==============
Name
Address
Age
AgeSex
======
Age
Sex
If I am understanding everything correctly, the solution might look kind of like this:
SELECT P.Name, P.Address, P.Phone, A.Age, S.Sex
FROM NameAddressPhone P
INNER JOIN NameAddressAge A ON P.Name = A.Name AND P.Address = A.Address
INNER JOIN AgeSex S ON A.Age = S.Age
Mind you, joining AgeSex could produce duplicate rows if there are multiple rows with the same age in AgeSex. There wouldn't be a way to distinguish 21 and Male from 21 and Female, for example.
I hope I can help and this is what you are looking for.

what is mapping in sql?

how to map tables in sql?
i have three tables . i want to map this tables using sql queries.
student 'table1'
Studnt_id password
123 5525
124 2233
student_info 'table 2'
Studnt_id student_name subject marks
123 gautam maths 90
124 gaurav maths 85
student_personal_info 'table 3'
firstname lastname address
gautam jethva banglore, karnataka
gaurav rathod jamnagar , gujarat
i want to map this three table and show in the result id, student_name , lastname,subject, marks, address
You need to JOIN (map) tables together; Jeff Atwood has a great overview of how these work in his article, "A Visual Explanation of SQL Joins"
In your example above, you should be able to use the studn_id column to link the tables student ('table1') and student_info ('table2') together. The third may be trickier as it doesn't appear to have a guaranteed key back to either of the first two tables.
Example:
SELECT S.student_name, S.subject, S.marks
FROM student S
INNER JOIN student_info SI ON S.Studnt_id = SI.Studnt_id
Will give you all the rows in student that have a matching row in student_info
However, linking the third table, student_personal_info is much harder. Your issue here is that there doesn't seem to be a unique way of pulling in the rows in this table for a specific student - you could try joining on name, but this isn't guaranteed to be unique.
The table student_personal_info really should have the column Studnt_id in it to make unique selection of rows for a specific student possible. Given your specific example, however, the following will work:
SELECT S.student_name, S.subject, S.marks, SPI.lastname, SPI.address
FROM student S
INNER JOIN student_info SI ON S.Studnt_id = SI.Studnt_id
INNER JOIN student_personal_info SPI ON SI.student_name = SPI.firstname
However, if more than one student shares the same first name, you'll get multiple matches.

SQL Server filtering

A new government reporting regulation requires you to develop a query that can count the number of male dependents of employees of the company. The information is stored in the dep_gender column of the dependent table. The result table should have a single output column labeled Number Male Dependents.
So for this part I have :
SELECT COUNT(DEP_GENDER)"Number of Male Dependents"
FROM dependent
where dep_gender = 'M';
which works just fine now to 'revise' for the next part.. I am having some problems because I cannot figure out how to filter into two different groups with associated counts for males and females.
A revision to the government reporting regulation requires the report to count the number of male and female dependents of the company. Display the information as two columns, one for gender and one for the associated count. The result table should have two rows, one for each gender. Use a single query. Additionally, the gender output column should be formatted as CHAR(6) and have a heading label of Gender. The count column should have a heading label of Number Counted.
I think you're looking for a Group By query:
Select Cast(Dep_Gender as Char(6)) as Gender,
Count(1) 'Number Counted'
From Dependent
Group By Cast(Dep_Gender as Char(6))
Cast is used since the requirements (homework perhaps) are to format the gender as a char(6).
SELECT 'Male' As [Gender], COUNT(DEP_GENDER) AS [Counted]
FROM dependent
where dep_gender = 'M'
UNION ALL
SELECT 'Female', COUNT(DEP_GENDER)
FROM dependent
where dep_gender = 'F'