SQL- how would i Join these two queries - sql

I have the following queries, and am attempting to join them
SELECT COUNTRY_NAME, COUNTRY_ID
FROM OEHR_COUNTRIES;
these results
COUNTRY_NAME CO
---------------------------------------- --
Argentina AR
Australia AU
Belgium BE
Brazil BR
Canada CA
Switzerland CH
China CN
Germany DE
Denmark DK
Egypt EG
France FR
HongKong HK
Israel IL
India IN
Italy IT
Japan JP
Kuwait KW
Mexico MX
Nigeria NG
Netherlands NL
Singapore SG
United Kingdom UK
United States of America US
Zambia ZM
Zimbabwe ZW
my second query
SELECT COUNTRY_ID, COUNT(COUNTRY_ID) AS "LCOUNT"
FROM OEHR_LOCATIONS
GROUP BY COUNTRY_ID;
results
CO LCOUNT
-- -------
US 4
SG 1
CA 2
CH 2
IT 2
MX 1
CN 1
DE 1
JP 2
IN 1
AU 1
UK 3
BR 1
NL 1
When i attempt to join these two results, so each country has the count after it
SELECT OEHR_COUNTRIES.COUNTRY_NAME, OEHR_COUNTRIES.COUNTRY_ID, COUNT(OEHR_LOCATIONS.COUNTRY_ID) AS LCOUNT
FROM OEHR_COUNTRIES
OUTER JOIN OEHR_LOCATIONS
ON OEHR_COUNTRIES.COUNTRY_ID = OEHR_LOCATIONS.COUNTRY_ID
ORDER BY LCOUNT;
i get this error
ON OEHR_COUNTRIES.COUNTRY_ID = OEHR_LOCATIONS.COUNTRY_ID
*
ERROR at line 4:
ORA-00904: "OEHR_COUNTRIES"."COUNTRY_ID": invalid identifier
ON OEHR_COUNTRIES.COUNTRY_ID = OEHR_LOCATIONS.COUNTRY_ID
*
ERROR at line 4:
ORA-00904: "OEHR_COUNTRIES"."COUNTRY_ID": invalid identifier
what is causing this error?
is there a simpler way to do what i am trying to achieve?

I assume this is something you need. It would list 0 for countries with no count. If you dont want to list countries with no count, use INNER JOIN
SELECT C.COUNTRY_NAME,
case
when L.LCOUNT is null
then 0
else L.LCOUNT
END as LCOUNT
FROM OEHR_COUNTRIES C
LEFT JOIN
(SELECT COUNTRY_ID, COUNT(COUNTRY_ID) AS LCOUNT
FROM OEHR_LOCATIONS
GROUP BY COUNTRY_ID) L
on C.COUNTRY_ID=L.COUNTRY_ID
order by LCOUNT DESC

You're missing the mandatory LEFT (or, in other scenarios, RIGHT) before the optional OUTER in the join syntax.
At the moment the word OUTER is being misinterpreted as a table alias, which is what is causing the error you're getting - there is, to the parser, now an OUTER.COUNTRY_ID but not a OEHR_COUNTRIES.COUNTRY_ID.
Add the missing word to stop it being seen as an alias, and to stop it defaulting to an inner join:
SELECT OEHR_COUNTRIES.COUNTRY_NAME, OEHR_COUNTRIES.COUNTRY_ID,
COUNT(OEHR_LOCATIONS.COUNTRY_ID) AS LCOUNT
FROM OEHR_COUNTRIES
LEFT OUTER JOIN OEHR_LOCATIONS
ON OEHR_COUNTRIES.COUNTRY_ID = OEHR_LOCATIONS.COUNTRY_ID
GROUP BY OEHR_COUNTRIES.COUNTRY_NAME, OEHR_COUNTRIES.COUNTRY_ID
ORDER BY LCOUNT;
I've added the missing group-by clause too. With your sample data that gets:
COUNTRY_NAME CO LCOUNT
------------------------ -- ----------
Belgium BE 0
Argentina AR 0
Zimbabwe ZW 0
...
Zambia ZM 0
Mexico MX 1
China CN 1
...
Germany DE 1
Switzerland CH 2
Canada CA 2
Japan JP 2
Italy IT 2
United Kingdom UK 3
United States of America US 4
25 rows selected.
Without adding that missing word, changing the other references to the table to use the (wrong) OUTER alias instead would have meant it would execute, again with the group-by clause added:
SELECT OUTER.COUNTRY_NAME, OUTER.COUNTRY_ID, COUNT(OEHR_LOCATIONS.COUNTRY_ID) AS LCOUNT
FROM OEHR_COUNTRIES
OUTER JOIN OEHR_LOCATIONS
ON OUTER.COUNTRY_ID = OEHR_LOCATIONS.COUNTRY_ID
GROUP BY OUTER.COUNTRY_NAME, OUTER.COUNTRY_ID
ORDER BY LCOUNT;
but it wouldn't have done quite what you wanted - assuming you want to see zero counts for countries with no locations - since it's now an inner join:
COUNTRY_NAME CO LCOUNT
------------------------ -- ----------
Netherlands NL 1
India IN 1
...
Australia AU 1
Switzerland CH 2
Japan JP 2
Canada CA 2
Italy IT 2
United Kingdom UK 3
United States of America US 4
14 rows selected.
The 11 countries with no locations aren't shown at all with an inner join.

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?

Constructing the SQL query below

GOALS (~1700 rows)
YEAR COUNTRY NAME NUM_GOALS
-------------------------------------------
2018 England Harry Kane 6
2018 France Antoine Griezmann 4
2014 Argentina Lionel Messi 4
2014 Brazil Fred 1
2010 Germany Thomas Muller 5
2010 Japan Shinji Okazaki 1
1992 England Gary Linekar 6
CHAMPIONS (~500 rows)
YEAR COUNTRY NAME ROLE
-------------------------------------------------
2018 France Didier Deschamps Manager
2018 France Hugo Lloris Goalkeeper
2018 France Paul Pogba Midfielder
2014 Germany Joachim Loew Manager
2014 Germany Mesut Ozil Midfielder
2014 Germany Miroslav Klose Forward
2002 Brazil Da Silva Midfielder
1994 Brazil Da Silva Midfielder
1998 France Didier Deschamps Midfielder
Write a query showing all world cup winning players who have never scored a goal.
What I am unsure about is whether to use a join for this and whether there is a need to specify and ID's if a join is to be used.
I'd be grateful for extra clarification and help with this, or if my query needs any tweaking.
What I have tried:
This is what I came up with:
SELECT GOALS.NAME
FROM GOALS
INNER JOIN CHAMPIONS ON CHAMPIONS.COUNTRY = GOALS.NAME
WHERE GOALS.NUM_GOALS = 0;
Problems with your query:
the join condition does not look right
even if it was, it searches for players that had at least one world cup without scoring a goal - which is different from those that never scored a goal
You could use not exists:
select c.*
from champions c
where not exists (
select 1
from goals g
where g.country = c.country and g.name = c.name and g.num_goals > 0
)
This assumes that (country, name) tuples do identify a player.
On the other hand, if you want players that won a world cup without scoring a goal in that particular event, then you can either add a correlation condition on year, or use a straight join:
select c.*
from champions c
inner join goals g
on g.country = c.country
and g.name = c.name
and g.year = c.year
where g.num_goals = 0
Your ON condition is comparing CHAMPIONS.COUNTRY = GOALS.NAME, which is not a good comparison for joining these two tables. I would suggest doing this:
SELECT
GOALS.NAME
FROM
GOALS
INNER JOIN
CHAMPIONS
ON
CHAMPIONS.COUNTRY = GOALS.COUNTRY
WHERE
GOALS.NUM_GOALS = 0;

sql select 1 item from list

i want to select a column from a table which can have another column reference many times.
select t1.name
from ccp.ENTITIES t1
Non
Albania
Australia
China
Czech Republic
Egypt
Germany
Greece
Group
Hungary
India
Ireland
Italy
Luxembourg
Malaysia
Malta
Netherlands
Portugal
Romania
Spain
Turkey
UK
US
this will give me a list of names of which i want 1 row from another table
v_networks_by_lm this table holds records with column t1.name and network. i want the column network only once for each item in the list. v_networks_by_lmcan hold many t1.name
entity name
a Spain
b Spain
c Spain
d Spain
e Spain
f Spain
g Spain
h Germany
i Germany
j Germany
k Germany
l Germany
m Germany
n Germany
o Germany
p UK
q Germany
r Spain
s Spain
t Portugal
u Portugal
v Portugal
q Portugal
from the above data which is in v_networks_by_lm i only want name returned once with any value of entity. but i want to pick the name from ENTITIES as it can be dynamic
I think aggregation does what you want:
SELECT MAX(n.network) as network, e.name
FROM ccp.ENTITIES e JOIN
ccp.v_networks_by_lm n
ON n.name = e.name
GROUP BY e.name;
Sounds like you want a subquery to get the single instance of name from the table, and then you do the join against entities.
Select sub.one_of_entity_values, sub.name
from ccp.entities e
inner join (
select max(entity) as one_of_entity_values, name
from v_networks_by_lm
group by name) sub on e.name = sub.name

How to make right outer join?

I am using OE schema and trying to see item # and quantity on hand in each warehouse and if any warehouse does not have item than it should show 0 item in hand. i am running following SQL and it is not showing 0 quantity for items.
select i.product_id,w.warehouse_name ,(i.quantity_on_hand)
from inventories i
right outer join warehouses w
on (i.warehouse_id=w.warehouse_id)
order by 1
I want to see result like this:
PRODUCT_ID WAREHOUSE_NAME NVL(I.QUANTITY_ON_HAND,0)
---------- ----------------------------------- -------------------------
2262 Sydney 35
2262 Beijing 50
2262 Bombay 35
2262 San Francisco 155
2262 Seattle, Washington 77
Toronto 0
New Jersey 0
Southlake, Texas 0
Mexico City 0
3501 Toronto 220
3501 Sydney 320
3501 Mexico City 294
3501 Beijing 268
3501 San Francisco 353
New Jersey 0
Southlake, Texas 0
Seattle, Washington 0
Bombay 0
You want to see a row for every warehouse and every product. So, start with generating this list and use left outer join to bring in the values that exist:
select i.product_id, w.warehouse_name, coalesce(i.quantity_on_hand, 0)
from warehouses w cross join
(select distinct product_id from inventories) p left join
inventories i
on w.warehouse_id = i.warehouse_id and p.product_id = i.product_id
order by i.product_id, w.warehouse_name;

How to do multi-table joins in MySQL involving composite foreign keys?

Sample tables are as follows:
SCENARIO_NATIONS
[scenID] [side] [nation]
scen001 1 Germany
scen001 2 Britain
scen001 2 Canada
SCENARIO_NEEDUNITS
[scenID] [unitID]
scen001 0001
scen001 0003
scen001 0107
scen001 0258
scen001 0759
UNIT_BASIC_DATA
[unitID] [nation] [name]
0001 Germany Mortars
0003 Germany Infantry
0107 Britain Lt
0258 Britain Infantry
0759 Canada Kilted Yaksmen
Goal: given a scenID, pull a list of units from the database sorted by side, nation, name.
I can do everything except for the side inclusion with:
SELECT scenario_needunits.scenID, unit_basic_data.nation, unit_basic_data.name
FROM scenario_needunits
LEFT OUTER JOIN unit_basic_data
ON scenario_needunits.unitID=unit_basic_data.unitID
WHERE scenario_needunits.scenID='scen001'
ORDER BY unit_basic_data.nation ASC, unit_basic_data.name ASC
I've tried just dropping the SCENARIO_NATIONS table in as a LEFT OUTER JOIN on scenID but what ends up happening is that ALL units come back with a side of 1 because that's always the first side listed for the scenID in the SCENARIO_NATIONS table.
Conceptually, what I think needs to happen is SCENARIO_NATIONS must be joined to both the scenID (to restrict it to just that scenario) and to each unit's nation but I don't have any idea how to do that.
OMG Ponies' code results in each unit being listed twice, once per side, rather than only for the side which its parent nation is on:
[scenID] [side] [nation] [name]
BaBu001 1 America CAPT
BaBu001 1 America HMG
BaBu001 1 Germany CAPT
BaBu001 1 Germany GREN
BaBu001 2 America CAPT
BaBu001 2 America HMG
BaBu001 2 Germany CAPT
BaBu001 2 Germany GREN
correct results would be
[scenID] [side] [nation] [name]
BaBu001 1 America CAPT
BaBu001 1 America HMG
BaBu001 2 Germany CAPT
BaBu001 2 Germany GREN
And to get that we modify the code like so:
SELECT sn.side, snu.scenid, ubd.nation, ubd.unitname
FROM sn
JOIN snu
ON snu.scenid=sn.scenid AND snu.scenid = 'scenID'
JOIN ubd
ON ubd.nation=sn.nation AND ubd.unitid=snu.unitid //double join is the key change
ORDER BY sn.side, ubd.nation, ubd.unitname
If you only want UNIT_BASIC_DATA rows/records with a relationship in the SCENARIO_NEEDUNITS table, use:
SELECT snu.scenid,
sn.side,
ubd.nation,
ubd.name
FROM UNIT_BASIC_DATA ubd
JOIN SCENARIO_NEEDUNITS snu ON snu.unitid = ubd.unitid
AND snu.scenid = ?
JOIN SCENARIO_NATIONS sn ON sn.scenid = snu.scenid
ORDER BY snu.scenid, sn.side, ubd.nation, ubd.name
Replace the ? with whatever scenid you wish to look for.
You don't need to specify ASC - it's the default.