TSQL Understanding the execution of the Query - sql-server-2005

I have two tables
Table Visitor
ID Name CityName
1 Jon NY
1 Jon KY
2 Paul NY
1 paul TY
Table City
ID CityName
1 NY
2 KY
3 TY
I have to list the visitor who has visited all cities in City Table.
I took the query from web,but i do not the how it works internally.
The query is
select distinct v1.name from Visitor v1
where not exists
(
select c.CityName from City c
where not exists
(
select v2.CityName from visitor v2 where
v2.CityName=c.CityName and v1.Name=v2.Name
)
)
Kinldy help me to understand the step
Iteration 1
Most outer query v1.Name=jon
outer query c.CityName=NY
inner query V2.CityName = c.CityName (NY=NY)
and v1.Name=v2.Name (Jon =Jon)
inner query return valye (i.e) v2.CityName=NY
NY not exists
(
NY
)
consition fails so nothing return
Iteration 2
Most outer query v1.Name=jon
outer query c.CityName=NY
inner query V2.CityName = c.CityName (KY=NY)
and v1.Name=v2.Name (Jon =Jon)
inner query return valye (i.e) v2.CityName=NULL
NY not exists
(
NULL
)
condition fails
(i.e) NOT Exists is true so Jon is returned from outer most query.
Am i right in understanding?

This is the relational division query popularised by Chris Date.
It basically uses a double negative. To rewrite what it is doing in English: It Selects all the Visitors where there is no city that they have not visited.

FYI, a simpler approach is:
select v1.name
from Visitor v
inner join City c on v.CityName = c.CityName
group by v1.Name
having count(distinct(c.CityName)) = 3

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 to get all cities in a country given a tree type databsae

I have been given a table like this
Id Name Type ParentId
1 US country -1
2 NY state 1
3 NYC city 2
4 Yonkers city 2
5 Washington state 1
6 Seattle city 5
7 Tacoma city 5
8 Canada country -1
9 Manitoba state 8
I want to write a sql query to write the all cities in a state.
Example
Country state city
US NY NYC
US NY Yonkers
I get that I need to write a recursive query but not able yo do so. I need help to write a sql for this.
You can use a recursive common table expression:
with recursive cte as (
select id, name, type, parentid
from the_table
where type = 'state'
and name = 'NY'
union all
select c.id, c.name, c.type, c.parentid
from the_table c
join cte p on p.id = c.parentid
)
select *
from cte
where type <> 'state';
The above is standard ANSI SQL, but not all database products support this exact syntax.
If the number of levels is fixed (so it's always Country -> State -> City) and will never change, you can use a simpler query:
select c.*
from the_table c
where parentid in (select s.id
from the_table s
where s.type = 'state'
and s.name = 'NY');
SELECT t1.name country, t2.name state, t3.name city
FROM table t1
JOIN table t2 ON t1.id = t2.parent_id
JOIN table t3 ON t2.id = t3.parent_id
WHERE t2.name = 'NY';

Need Simple SQL direction

I'm trying to write a Ado SQL statement for my Access table and I'm getting the wrong results.
Employee Table
ID Name DriverID
1 Alex 1
2 Tom 2
3 Trevor 3
4 PHIL 0
5 Gina 4
Vehicle Table
ID PLATE EMPLOYEEID INSERVICE
1 123XYZ 1 N
2 456GFR 2 Y
3 TFV4FG 3 Y
4 F6GK7D 4 Y
5 GEY7GH 1 Y
I want result of All employes and to display the Vehcicle info if they are assigned to it.
Result should be
Name Plate
Alex GEY7GH
Tom 456GFR
Trevor TFV4FG
PHIL
Gina F6GK7D
SELECT Employee.ID, Employee.FirstName, Vehicles.Plate, Vehicles.InService
FROM Employee LEFT JOIN Vehicles ON Employee.ID = Vehicles.DriverID
WHERE (((Vehicles.InService)=True));
Does not display PHIL who is not assigned to a vehicle.
Just add the condition inside the join, making sure to use parentheses to avoid problems when joining with constants or anything but simple equals:
SELECT Employee.ID, Employee.FirstName, Vehicles.Plate, Vehicles.InService
FROM Employee LEFT JOIN Vehicles ON (Employee.ID = Vehicles.DriverID AND Vehicles.InService = True)
From the above tables, it looks like the DriverID Column in employee table aligns with the EmployeeID column in the vehicles table and the issue is the on clause in the join.
SELECT
Employee.ID
,Employee.FirstName
,Vehicles.Plate
,Vehicles.InService
FROM
Employee
LEFT JOIN Vehicles ON Employee.DRIVERID = Vehicles.EMPLOYEEID
WHERE
(((Vehicles.InService)=True));
Well, in a normal database, you would move the WHERE condition to the ON clause. But I don't think that MS Access supports this:
SELECT e.ID, e.FirstName, v.Plate, v.InService
FROM Employee as e LEFT JOIN
Vehicles as v
ON e.ID = v.DriverID AND v.InService = True;
An alternative is a subquery:
SELECT e.ID, e.FirstName, v.Plate, v.InService
FROM Employee as e LEFT JOIN
(SELECT v.*
FROM Vehicles as v
WHERE v.InService = True
) as v
ON e.ID = v.DriverID ;

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

Trying to find all the cities that there is not a direct flight to from a city (PostgreSQL)

I'm trying to write a query that determines which cities I can't fly to directly from a city, say London. Given the schema:
cities:
| c_id | city_name |
flights:
| f_id | departure_city_id | destination_city_id |
currently my query returns the opposite, i.e. it returns the cities for which there is a direct flight from London
SELECT c2.city_name as "City"
FROM flights AS f
JOIN cities AS c2 ON f.destination_city_id != c2.c_id
JOIN cities AS c ON c.c_id = c.c_id
WHERE c.city_name = 'London'
AND c.c_id != c2.c_id
AND f.departure_city_id = c.c_id;
I would have thought it would be easy to change it to get what I want.
I thought changing the third line to
JOIN cities AS c2 ON f.destination_city_id = c2.c_id
Would have done the trick but it didn't. Any help?
cities I can't fly to directly from a city, say London.
Meaning one can fly there, just not directly from London. So JOIN (not LEFT JOIN) city to flight via destination_city_id:
SELECT DISTINCT c.city_name
FROM cities c
JOIN flights f ON f.destination_city_id = c.c_id
JOIN cities c2 ON c2.c_id = f.departure_city_id
WHERE c2.city_name <> 'London';
Then I only have to exclude flights originating from London, apply DISTINCT to get unique city names and we are done.
A more sophisticated interpretation of this question would be:
"Cities you can fly to from London, just not directly"
But since this looks like basic homework I don't assume they'd expect a recursive query from you.
Try something like:
SELECT *
FROM cities c
WHERE c.c_id NOT IN
(SELECT f.destination_city_id
FROM flights f
JOIN cities c2 ON f.departure_city_id = c.c_id
WHERE c2.city_name = 'London')