SQL Query - in how many countries we have users and in how many countries we don't have users - sql

Need a SQL query that will answer this question.
Please tell us in how many countries we have users and in how many countries we don't have users. This should be presented in a table, in a single row and two columns (one with the number of countries in which we have users and one with the number of countries where we don't have users).
We have two tables: AllCountriesInTheWorld and AllUsers.
Table AllCountriesInTheWorld
country_id
country_name
1
USA
2
France
3
Italy
4
Portugal
5
Spain
6
Canada
7
UK
8
China
9
Japan
10
Germany
Table AllUsers
user_id
user_name
country_id
a1
John
4
b2
Jane
6
c3
Tony
6
d4
Dan
9
e5
Dave
1
Thanks a lot in advance guys!

If you LEFT JOIN the 2 tables on their common key,
then you can get all countries with or without users.
select *
from AllCountriesInTheWorld ctry
left join AllUsers usr
on usr.country_id = ctry.country_id
country_id
country_name
user_id
user_name
country_id
1
USA
e5
Dave
1
2
France
null
null
null
3
Italy
null
null
null
4
Portugal
a1
John
4
5
Spain
null
null
null
6
Canada
b2
Jane
6
6
Canada
c3
Tony
6
7
UK
null
null
null
8
China
null
null
null
9
Japan
d4
Dan
9
10
Germany
null
null
null
If you then GROUP BY the countries then you can COUNT how many USER_ID each country has.
count(usr.user_id) as total_users
country_id
total_users
1
1
2
0
3
0
4
1
5
0
6
2
7
0
8
0
9
1
10
0
Then just wrap that in a CTE or sub-query and use conditional aggregation on the total users.
;with CTE_COUNTRIES as (
...
)
select
sum(case when total_users > 0 then 1 else 0 end) as countries_with_users
, sum(case when total_users = 0 then 1 else 0 end) as countries_without_users
from CTE_COUNTRIES
countries_with_users
countries_without_users
4
6

Related

How to get the list of people who do NOT have citizenship of country X in SQL

I have the 3 following tables
People
Id
Name
Age
1
Bob
23
2
John
25
3
Fred
37
4
Avery
42
Citizenship
Person_ID
Country_ID
1
2
1
1
2
1
2
5
3
2
3
6
4
3
4
4
Country
Country_ID
Country_Name
Capital_City
1
UK
London
2
France
Paris
3
Canada
Ottawa
4
Australia
Canberra
5
Germany
Berlin
6
Russia
Moscow
The goal here is to find all people who do NOT have French citizenship. My initial query was as follows
SELECT p.name
FROM People p
LEFT JOIN Citizenship ct
ON p.id = ct.person_id
LEFT JOIN Country c
ON ct.country_id = c.country_id
WHERE c.country_name != 'France';
However, the result doesn't seem to be correct. What condition am I missing in this query?

How retrieve all parent and child rows population in Oracle sql?

I have a table "TB_Population" with some records about the population from all over the world.
at this time I want to calculate each title's population in particular row
and demonstrate each level in that table.
I have this table with the following data:
ID TITLE PARENT_ID POPULATION
1 WORLD 10
2 AFRICA 1 5
3 ASIA 1 10
4 EUROPE 1 4
5 GERMANY 4 6
6 FRANCE 4 10
7 ITALY 4 4
8 JAPAN 3 6
9 MORROCO 2 1
10 SPAIN 4 9
11 INDIA 3 8
12 PORTUGAL 4 2
13 USA 14 10
14 AMERICA 1 10
15 NEWYORK 13 5
The expected output table should be as below
ID TITLE POPULATION LEVEL
1 WORLD 100 1
2 AFRICA 6 2
3 ASIA 24 2
4 EUROPE 35 2
5 GERMANY 6 3
6 FRANCE 10 3
7 ITALY 4 3
8 JAPAN 6 3
9 MORROCO 1 3
10 SPAIN 9 3
11 INDIA 8 3
12 PORTUGAL 2 3
13 USA 15 3
14 AMERICA 25 2
15 NEWYORK 5 4
Thanks and best regards
The tricky part which I see here is you want the LEVEL of title from "BOTTOM TO TOP" and POPULATION from "TOP TO BOTTOM". For example, AMERICA's level has to be 2 which means the LEVEL has to be measured from AMERICA -> WORLD, but AMERICA's population has to be 25 which is the sum of population measured from AMERICA -> NEWYORK. So, I tried this:
SELECT TOP_TO_BOTTOM.TITLE_ALIAS, TOP_TO_BOTTOM.TOTAL_POPULATION, BOTTOM_TO_TOP.MAX_LEVEL FROM
(SELECT TITLE_ALIAS, SUM(POPULATION) AS "TOTAL_POPULATION" FROM
(SELECT CONNECT_BY_ROOT TITLE AS "TITLE_ALIAS", POPULATION
FROM TB_POPULATION
CONNECT BY PRIOR ID = PARENT_ID)
GROUP BY TITLE_ALIAS) "TOP_TO_BOTTOM"
INNER JOIN
(SELECT TITLE_ALIAS, MAX(LEV) AS "MAX_LEVEL" FROM
(SELECT CONNECT_BY_ROOT TITLE AS "TITLE_ALIAS", LEVEL AS "LEV"
FROM TB_POPULATION
CONNECT BY PRIOR PARENT_ID = ID)
GROUP BY TITLE_ALIAS) "BOTTOM_TO_TOP"
ON
BOTTOM_TO_TOP.TITLE_ALIAS = TOP_TO_BOTTOM.TITLE_ALIAS
ORDER BY BOTTOM_TO_TOP.MAX_LEVEL;
You can have a look at the simulation here: https://rextester.com/HFTIH47397.
Hope this helps you

How to join different table some column?

Student Table 1
ID Name Surname School Number Class Number ClassBranch
-----------------------------------------------------------------------------
113 Jane Smith 19 4 A
121 John Konl 42 5 B
331 Albert Smith 61 4 A
742 Jack Ronal 52 5 B
759 Jan Ronal 84 6 C
Student Table 2
ID Name Surname School Number Class Number Class Branch
-----------------------------------------------------------------------------
113 Jane Smith 11 4 D
151 John Konl 18 4 D
804 Albert Smith 26 5 F
605 Jack Ronal 32 5 F
785 Jan Ronal 87 8 L
Created Student Table
ID Name Surname School Number Class Number Class Branch
--------------------------------------------------------------------
113 Jane Smith NULL NULL NULL
151 John Konl NULL NULL NULL
804 Albert Smith NULL NULL NULL
605 Jack Ronal NULL NULL NULL
NULL NULL NULL 11 4 D
NULL NULL NULL 18 4 D
NULL NULL NULL 26 5 F
NULL NULL NULL 32 5 F
I want this table
ID Name Surname School Number Class Number Class Branch
113 Jane Smith 11 4 D
151 John Konl 18 4 D
804 Albert Smith 26 5 F
605 Jack Ronal 32 5 F
I want to Student Table 1 ---> ID,Name,Surname and Student Table 2 --> School Number,Class Number and ClassBranch joın.But joın is not successful.Class Branch A and B removed and D,F is adding.
First table ID,Name,Surname (3 columns) and Second table School Number,Class Number,Class Branch join.
Where conditions:
Removed column --> 4 - A AND 5 - B
Adding column --> 4- D AND 5- F
How can I write query?
Now that you've completely changed the original tables, this should be a simple JOIN.
SELECT t2.id, t1.name, t1.surname, t2.SchoolNumber, t2.ClassNumber, t2.ClassBranch
FROM Student1 AS t1
JOIN Student2 AS t2 ON t1.name = t2.name AND t1.surname = t2.surname
DEMO
To get those results?
1) The complicated way. By joining them.
SELECT
s2.ID,
s1.Name, s1.Surname,
s2."School Number", s2."Class Number", s2.ClassBranch
FROM Student1 AS s1
JOIN Student2 AS s2 ON (s2.Name = s1.Name AND s2.Surname = s1.Surname)
WHERE s1."Class Number" IN (4, 5);
2) The simple way, select only from the 2nd table
SELECT *
FROM Student2
WHERE "Class Number" IN (4, 5);
Test on SQL Fiddle here

How to get sum of the same Unit's

I have a table which contains a college's departments and their units and sub-units.
OrganizationID ParentUnit Unit ChildUnit UnitName
10 1 0 0 Education
12 1 1 0 Sports
24 1 2 0 Mathmatics
28 1 3 0 Science
35 1 3 1 Physics
51 1 4 0 Arts
66 1 4 1 Music
69 1 4 2 Painting
84 8 0 0 Business & Administration
88 8 1 0 Administration
96 8 1 1 Public Administration
107 8 1 2 Local Managements
110 8 2 0 Finance
119 8 2 1 Accounting
124 8 2 2 Marketing
I have another table which contains the student information of that college.
StudentID OrganizationID
1 12
2 12
3 24
5 28
6 35
8 51
9 66
31 69
34 96
45 88
57 96
66 107
69 110
72 69
74 124
I want to get student counts for each unit. If a studutent's Organization is a ChildUnit it should be added to current Unit. If ChildUnit is greater than0 corresponding student count should be added to same Unit For example Physics is a child of Science. Then Science student count should return 2.
My target data table should look like as the following
ParentUnit UnitName StudentCount
------------------------------------------------------
Education Sports 2
Education Mathmatics 1
Education Science 2
Education Arts 4
Business & Administration Administration 4
Business & Administration Finance 2
I have done it in programmatic way. There are many for and if loops. Then I started to think whether it could be done with a smarter sql query.
That doesn't look so difficult. You are looking for the student count per ParentUnit + Unit. Then the name for such a group is the record where the level (the ChildUnit) is zero. You get that record with a CASE construct, then use MIN or MAX, because you need an aggregate function here (there should be exactly one record per group anyhow, so MIN = MAX).
select
min(case when o.childunit = 0 then o.unitname end) as unitname,
count(*) as studentcount
from organization o
inner join student s on s.organizationid = o.organizationid
group by o.parentunit, o.unit;
To include the parent unit name:
select
(
select unitname
from organization po
where po.parentunit = o.parentunit
and po.unit =0
and po.childunit = 0
) as parentunitname,
min(case when o.childunit = 0 then o.unitname end) as unitname,
count(*) as studentcount
from organization o
inner join student s on s.organizationid = o.organizationid
group by o.parentunit, o.unit;
Or:
select
min(po.unitname) as parentunitname,
min(case when o.childunit = 0 then o.unitname end) as unitname,
count(*) as studentcount
from organization o
inner join student s on s.organizationid = o.organizationid
inner join
(
select parentunit, unitname
from organization
where unit = 0 and childunit = 0
) po on po.parentunit = o.parentunit
group by o.parentunit, o.unit;

SQL : How to find number of occurrences without using HAVING or COUNT?

This is a trivial example, but I am trying to understand how to think creatively using SQL.
For example, I have the following tables below, and I want to query the names of folks who have three or more questions. How can I do this without using HAVING or COUNT? I wonder if this is possible using JOINS or something similar?
FOLKS
folkID name
---------- --------------
01 Bill
02 Joe
03 Amy
04 Mike
05 Chris
06 Elizabeth
07 James
08 Ashley
QUESTION
folkID questionRating questionDate
---------- ---------- ----------
01 2 2011-01-22
01 4 2011-01-27
02 4
03 2 2011-01-20
03 4 2011-01-12
03 2 2011-01-30
04 3 2011-01-09
05 3 2011-01-27
05 2 2011-01-22
05 4
06 3 2011-01-15
06 5 2011-01-19
07 5 2011-01-20
08 3 2011-01-02
Using SUM or CASE seems to be cheating to me!
I'm not sure if it's possible in your current formulation, but if you add a primary key to the question table (questionid) then the following seems to work:
SELECT DISTINCT Folks.folkid, Folks.name
FROM ((Folks
INNER JOIN Question AS Question_1 ON Folks.folkid = Question_1.folkid)
INNER JOIN Question AS Question_2 ON Folks.folkid = Question_2.folkid)
INNER JOIN Question AS Question_3 ON Folks.folkid = Question_3.folkid
WHERE (((Question_1.questionid) <> [Question_2].[questionid] And
(Question_1.questionid) <> [Question_3].[questionid]) AND
(Question_2.questionid) <> [Question_3].[questionid]);
Sorry, this is in MS Access SQL, but it should translate to any flavour of SQL.
Returns:
folkid name
3 Amy
5 Chris
Update: Just to explain why this works. Each join will return all the question ids asked by that person. The where clauses then leaves only unique rows of question ids. If there are less than three questions asked then there will be no unique rows.
For example, Bill:
folkid name Question_3.questionid Question_1.questionid Question_2.questionid
1 Bill 1 1 1
1 Bill 1 1 2
1 Bill 1 2 1
1 Bill 1 2 2
1 Bill 2 1 1
1 Bill 2 1 2
1 Bill 2 2 1
1 Bill 2 2 2
There are no rows where all the ids are different.
however for Amy:
folkid name Question_3.questionid Question_1.questionid Question_2.questionid
3 Amy 4 4 5
3 Amy 4 4 4
3 Amy 4 4 6
3 Amy 4 5 4
3 Amy 4 5 5
3 Amy 4 5 6
3 Amy 4 6 4
3 Amy 4 6 5
3 Amy 4 6 6
3 Amy 5 4 4
3 Amy 5 4 5
3 Amy 5 4 6
3 Amy 5 5 4
3 Amy 5 5 5
3 Amy 5 5 6
3 Amy 5 6 4
3 Amy 5 6 5
3 Amy 5 6 6
3 Amy 6 4 4
3 Amy 6 4 5
3 Amy 6 4 6
3 Amy 6 5 4
3 Amy 6 5 5
3 Amy 6 5 6
3 Amy 6 6 4
3 Amy 6 6 5
3 Amy 6 6 6
There are several rows which have different ids and hence these get returned by the above query.
you can try sum , to replace count.
SELECT SUM(CASE WHEN Field_name >=3 THEN field_name ELSE 0 END)
FROM tabel_name
SELECT f.*
FROM (
SELECT DISTINCT
COUNT(*) OVER (PARTITION BY folkID) AS [Count] --count questions for folks
,a.folkID
FROM QUESTION AS q
) AS p
INNER JOIN FOLKS as f ON f.folkID = q.folkID
WHERE p.[Count] > 3