How to select all rows but join information under condition - sql

Simplified I have two tables NAMES (with columns ID and NAME) and ADRESSES (with columns COUNTRY and CITY and NAME_ID).
Example for NAMES:
1 - Hans
2 - Mark
3 - Joseph
Example for ADRESSES:
Denmark - Kopenhagen - 1
Germany - Berlin - 3
I need to select all Names which either have no adress at all OR with their CITY but only when their country is... Denmark.
SELECT
NA.NAME AS NAME,
AD.CITY AS CITY
FROM NAMES AS NA
LEFT JOIN ADRESSES AS AD ON AD.NAME_ID = NA.ID
now when I add something like
WHERE AD.COUNTRY="Denmark"
or
WHERE (AD.COUNTRY="Denmark" OR AD.COUNTRY=NULL)
I still only get a list of Names with Cities in Denmark but not all other Names which have no Adress/City at all.
When I remove the condition of course I get all Names and existing Cities but even in all other countries.
The desired result would be:
Hans - Kopenhagen
Mark - NULL

I guess you mean WHERE AD.COUNTRY='Denmark' not WHERE AD.CITY='Denmark'. Also, Using WHERE clause with LEFT JOIN makes it like INNER JOIN. So shift your condition to LEFT JOIN clause -
SELECT NA.NAME AS NAME,
AD.CITY AS CITY
FROM NAMES AS NA
LEFT JOIN ADRESSES AS AD ON AD.NAME_ID = NA.ID
WHERE AD.COUNTRY='Denmark' OR AD.COUNTRY IS NULL

I need to select all Names which either have no adress at all OR with their CITY but only when their country is... Denmark.
I believe you want:
SELECT NA.NAME AS NAME, AD.CITY AS CITY
FROM NAMES NA LEFT JOIN
ADRESSES AD
ON AD.NAME_ID = NA.ID
WHERE AD.COUNTRY = 'DENMARK' OR AD.COUNTRY IS NULL;
This should not return names in other countries, such as Germany.

Related

How can I create a BigQuery record with a join, but without specifying all fields?

Question: How to join tables using join clause without listing all the fields?
Data
Given two tables, Person and Address:
Person
name
address_id
Alice
10
Bob
11
Charlie
10
Address
id
street
city
10
William Street
NYC
11
Old Street
London
Desired result:
I'd like to join them with a record, like so:
name
address.street
address.city
Alice
William Street
NYC
Bob
Old Street
London
Charlie
William Street
NYC
However, I have many columns in both tables and I don't want to specify them all.
So something a bit like using EXCEPT but with the joined columns becoming nested in an address record:
SELECT * EXCEPT (address_id)
FROM person p
JOIN address a
ON p.address_id = a.id
Is this possible in BigQuery?
Consider below query:
SELECT p.* EXCEPT(address_id), (SELECT AS STRUCT a.* EXCEPT(id)) AS address
FROM Person p JOIN Address a ON p.address_id = a.id;
output:
You can join more tables with similar approach.
SELECT p.* EXCEPT(address_id),
(SELECT AS STRUCT a.* EXCEPT(id)) AS address,
(SELECT AS STRUCT j.* EXCEPT(name)) AS Job
FROM Person p
JOIN Address a ON p.address_id = a.id
JOIN Job j ON p.name = j.name;
output:

SQL query to list cities in which employee did not work

SQL query to list cities in which employee did not work from below
"employee" table:
name
city
srini
seattle
ross
atlanta
rich
redmond
Example: if I give "srini", query should return "Atlanta" and "Redmond"
I tried below 2 queries with no luck, it returns empty results:
SELECT t1.city
FROM employee t1
JOIN employee t2 ON t1.name=t2.name
WHERE t1.city != t2.city
WHERE name='srini'
SELECT city
FROM (SELECT city FROM employee WHERE name='srini') as e1
WHERE city <> e1.city
This should work:
select distinct city
from employee
where city not in
(select city
from employee
where name = 'srini')
Basically it's selecting all city names that don't exist in a row where name is 'srini'
SQL is such fun. I'd go with a GROUP BY query, where I use the HAVING clause to only return cities where no srini lives.
select city
from employee
group by city
having sum(case when name = 'srini' then 1 else 0 end) = 0
Core ISO/ANSI SQL, i.e. every dbms is expected to support it.
Or use EXCEPT:
select city from employee
EXCEPT
select city from employee where name = 'srini'
Core ISO/ANSI SQL, i.e. every dbms is expected to support it.

SQL employee / company/country

I have three tables
Country (country id - country name - country pop)
City (city id - city name - city code - city pop)
Company (city code - company name - company employee)
Company employee is the number of employee.
I must present a table with the SUM of the employees that has each company in country level.
I have used the following query
SELECT country_name, company_name, company_employee
FROM country,
city,
company
WHERE country.country_id = city.country_id
and city.city_code = company.city_code
I took a table in which you can see the country, the company and the number of employee
(e.g. In one country UK the same company ACS has 2 records ACS 300 EMPLOYEE & ACS 100 EMPLOYEE instead of one record ACS 400 employee)
I believe that something is missing from my code. I have tried use functions such as sum and group but it failed.
Is this what you want?
SELECT cy.country_name, co.company_name, SUM(co.company_employee)
FROM company co JOIN
city ci
ON ci.city_code = co.city_code JOIN
country cy
ON cy.country_id = ci.country_id
GROUP BY cy.country_name, co.company_name;
Note the use of proper, explicit, modern, standard JOIN syntax. Never use commas in the FROM clause. This is particularly important if you are learning SQL; you should learn to use the language correctly.

How to join full name with shortcut

I have two tables, first with full names of countries (only one column):
Poland
Germany
Czech Republic
and second table with shortcuts of those names
PL
DE
CZ
How to join those two tables to one with two columns: country and country shortcut?
Poland PL
Germany DE ect
If the first table is named country, the second table is called abbr and the third table called table3 to find the abbrivation from the name it would look like this.
SELECT *
FROM country AS c
JOIN table3 as t3 on c.country = T3.country
JOIN abbr AS a on a.abbrivation = T3.abbrivation

Non-Equi Self Join

I have the following user table
USERS
name city
A New York
B Paris
C London
D London
E Paris
I want to select the two users from the same City using non equi self join
such that the result follows
name name city
B E Paris
C D London
A "self-join" is just like a normal join execpet that the same table appears on both sides of the join clause. "non-equi" means finding rows which don't match on some column.
So in your case you need to join on CITY and filter on differences in NAME:
select t1.name as t1_name
, t2.name as t2_name
, t1.city
from users t1
join users t2
on t2.city = t1.city
where t1.name < t2.name
Note the filter condition is less than: using not equals would double the result set.(*)
Obviously this solution will work where CITY has two entries. If there are more than two entries you will still get multiple rows (one per combination).
(*) Some times using != is desirable: if we're investigating a data quality issue then returning all columns from both rows can help us understand what's going on.
You can use below way with the use of cte also
WITH CITY
AS (
SELECT ROW_NUMBER() OVER(PARTITION BY A.CITY ORDER BY A.CITY) RNO,A.NAME,A.CITY FROM Table1 A
)
SELECT A.NAME,B.NAME,A.CITY FROM
CITY A JOIN
CITY B
ON
A.city=B.city AND A.NAME<>B.name AND A.RNO<=B.RNO