self join after an inner join - sql

I am finding what cities have the same name in different states. The city name and state name are in seperate tables (cities and states) and can be inner joined over a seperate common column.
select c1.city, c1.state, c2.city, c2.state
from cities
inner join states on cities.commonid = states.commonid
After inner joining i need to self join to perform a function as follows
select c1.city, c1.state, c2.city, c2.state
from *joined table* c1 join
*joined table* c2
on c1.city = c2.city and c1.state <> c2.state
i am wondering how i can self join a table that is the result of another join in the same query
output will be like this
+----------+-------+--------+--------+
| city1 | state1|city2 |state2 |
+----------+-------+--------+--------+
| x | melb | x | syd |
| y | bris | y | ACT |
+----------+-------+--------+--------+

I assume that the table cities has a column like state_id that references a column state_id in the table states (change the names to the actual names of the columns).
First do a self join for cities with the conditions:
c1.city = c2.city AND c1.state_id < c2.state_id
The < operator makes sure that each pair of cities wil be returned only once.
Then join 2 copies of states, because each of them will be used to get the name of the state for each of the 2 cities:
SELECT c1.city city1, s1.state state1,
c2.city city2, s2.state state2
FROM cities c1
INNER JOIN cities c2 ON c1.city = c2.city AND c1.state_id < c2.state_id
INNER JOIN states s1 ON s1.state_id = c1.state_id
INNER JOIN states s2 ON s2.state_id = c2.state_id
ORDER BY city1

You can do select of your inner join query and give it alias.
Then it will become something like below...
Select c.city,c.state from
(Select City,state from cities inner join states where cities.id = states.id) as c
Now make a self join for c.

I would perform a pre-query of all cities that have more than one state. Then join to the states table to see which states they are encountered.
select
Duplicates.city,
s.state
from
( select c1.city
from cities c1
group by c1.city
having count(*) > 1 ) Duplicates
JOIN cities c2
on Duplicates.city = c2.city
JOIN states s
on c2.commonid = s.commonid
order by
Duplicates.city,
s.state
By NOT trying to do cross-tab of just two city/states, you would get a single list. If one city name exists in 5 states, how would you plan on showing that. This way you would see all alphabetized.

I would suggest a CTE:
with cs as (
select c.name as city_name, s.name as state_name
from cities c join
states s
on c.commonid = s.commonid
)
select cs1.*, cs2.*
from cs cs1 join
cs cs2
on cs1.name = cs2.name and cs1.state <> cs2.state;

Related

identify stores not selling a product

I have 2 tables city_products that contains all products in the city and product_list that contains all the products that exist in different cities.I want a list of products not available in each city.
[![enter image description here][1]][1]
Table 1: city_prd
city product
------ -------
city 1 p1
city 1 p3
city 1 p2
city 2 p1
city 2 p5
Table 2: pdt_list
product
-------
p1
p2
p3
p4
p5
Desired output:
city product
------ -------
city 1 p4
city 1 p5
city 2 p2
city 2 p3
city 2 p4
I know its something to do with a cross join but I am not getting the exact answer
This is a variation of TheImpaler's answer, but it should work in all databases. Use a cross join to generate all combinations of cities and products. Then use left join (or a similar mechanism) to remove the ones that exist:
select c.city, p.product
from (select distinct city from city_prd) c cross join
pdt_list p left join
city_prd cp
on c.city = cp.city and p.product = cp.product
where cp.city is null;
I am also guessing that you have a cities table of some sort. You can use that instead:
select c.city, p.product
from cities c cross join
pdt_list p left join
city_prd cp
on c.city = cp.city and p.product = cp.product
where cp.city is null;
You don't mention which database you are using, so I'll give you a generic SQL solution. You can adapt it to your specific RDBMS.
select
c.city, p.product
from (
select distinct city from city_prd
) c
cross join pdt_list p
except
select city, product from city_prd
order by c.city, p.product

my sql query is not working according

sql structure
SELECT
opreator.o_name,
city.c_name as dept,
city.c_name as destination,route.fare
FROM opreator
INNER JOIN route ON opreator.id=route.id
LEFT OUTER JOIN city ON city.id=route.dep
i want to print data as
o_name| dep| dest|fare
You should use two join on city using table alias
SELECT
opreator.o_name,
c1.c_name as dep,
c2.c_name as destination,
route.fare
FROM route
INNER JOIN opeator on opreator.id=route.id
INNER JOIN city as c1 on c1.id = route.dep
INNER JOIN city as c2 on c2.id = route.dest
When you JOIN two tables together the condition should be something like WHERE table1.foreign_key = table2.primary_key.
Your first join has a condition WHERE table1.primary_key = table2.primary_key which doesn't make sense. The primary key for one table has nothing to do with the primary key of the other table.
You also need to join to the city table twice, once for dep and again for dest.
Try this:
SELECT opreator.o_name, c1.c_name as dept, c2.c_name as destination, route.fare
FROM route
JOIN opreator ON route.opreator = opreator.id
JOIN city c1 ON route.dep = c1.id
JOIN city c2 ON route.dest = c2.id

Need assistance with aggregate Count function

I have been doing nice little project to calculate the number of shipments per country made under particular office. I prefer to write a single query because otherwise it will take forever to process whole the data using while / for loops etc.
For this reason I wrote a query as following:
SELECT
COUNTRY.Code, COUNTRY.Name,
(SELECT COUNT(Shipment.Ref) FROM Shipment
LEFT JOIN Station (NOLOCK) ON Station.STID = Shipment.STDEST
LEFT JOIN Country (NOLOCK) ON Station.Code = Country.Code
LEFT JOIN Client (NOLOCK) ON Client.CID = Shipment.CID
WHERE Client.CBUR = 'UKLON'
) AS NumOrder
FROM COUNTRY
And this return a total number of shipments and not per particular country
--------------------------------------
|Code |Name |NumOrder|
--------------------------------------
| BE |BELGIUM | 82460 |
| FR |FRANCE | 82460 |
| UK |UNITED KINGDOM | 82460 |
| NL |NETHERLANDS | 82460 |
| AZ |AZERBAIJAN | 82460 |
| HK |HONG KONG | 82460 |
| AU |AUSTRALIA | 82460 |
| RE |REUNION ISLAND | 82460 |
I really appreciate if anyone would give me a hint how to modify the existing query to be able to count those shipment per country based on the given office account .
Try adding the Country in the Count
SELECT
COUNTRY.Code, COUNTRY.Name,
(SELECT COUNT(Shipment.Ref) FROM Shipment
LEFT JOIN Station (NOLOCK) ON Station.STID = Shipment.STDEST
LEFT JOIN Country (NOLOCK) ON Station.Code = TPAY.Code
LEFT JOIN Client (NOLOCK) ON Client.CID = Shipment.CID
WHERE Client.CBUR = 'UKLON' and Country.Name = C.Name --or this "and Country.Code = C.Code"
) AS NumOrder
FROM COUNTRY C
Smth. like this, in one request, consider group by clause:
SELECT
COUNTRY.Code, COUNTRY.Name, COUNT(Shipment.Ref)
FROM Country
-- joins go here: Shipment etc.
GROUP BY COUNTRY.Code, COUNTRY.Name
Change it to:
SELECT
C.Code, C.Name,
(
SELECT COUNT(Shipment.Ref) FROM Shipment
LEFT JOIN Station (NOLOCK) ON Station.STID = Shipment.STDEST
LEFT JOIN Client (NOLOCK) ON Client.CID = Shipment.CID
WHERE Client.CBUR = 'UKLON' AND Station.Code=C.Code
) AS NumOrder
FROM COUNTRY C
OR Use Group By:
SELECT
C.Code, C.Name,
COUNT(Shipment.Ref) AS NumOrder
FROM Shipment
LEFT JOIN Station (NOLOCK) ON Station.STID = Shipment.STDEST
LEFT JOIN Client (NOLOCK) ON Client.CID = Shipment.CID
LEFT JOIN COUNTRY C ON Station.Code=C.Code
WHERE Client.CBUR = 'UKLON'
GROUP BY C.Code
These are my assumptions:
STID is Station's primary key.
CID is Client's primary key.
TPAY is supposed to be Country.
Code is Country's primary key.
So your left joins return one record anyway (the matching one or a dummy empty one). Outer joins make no sense in your query.
You are not correlating your subquery to your main query, i.e. you are not selecting records within for the country without. You'd have to add this to your WHERE clause in your subquery.
SELECT
COUNTRY.Code,
COUNTRY.Name,
(
SELECT COUNT(*)
FROM Shipment
JOIN Station ON Station.STID = Shipment.STDEST
WHERE Station.Code = COUNTRY.Code
AND Shipment.CID IN (SELECT CID FROM Client WHERE CBUR = 'UKLON')
) AS NumOrder
FROM COUNTRY;
And here is the same thing with the subquery in the FROM clause instead:
SELECT
COUNTRY.Code,
COUNTRY.Name,
counted.NumOrder
FROM COUNTRY
JOIN
(
SELECT Station.Code, COUNT(*) AS NumOrder
FROM Station
JOIN Shipment ON Shipment.STDEST = Station.STID
AND Shipment.CID IN (SELECT CID FROM Client WHERE CBUR = 'UKLON')
GROUP BY Station.Code
) counted ON counted.Code = COUNTRY.Code;

Retrive counts of two columns from two diffrent tables with third table using join query in SQL

I have 3 tables: COUNTRY, STATE, CITY
This is my Country table with two columns:
CountryID, Name
This is my State table:
This is my City table:
I want to retrieve the count of states and cities according to the country table using join query.
Skipping the fact that your question is not asked well - try this query, it should work for you:
WITH
tab_a AS (
SELECT c.countryid, COUNT (s.stateid) AS state_num
FROM country c
LEFT JOIN state s ON c.countryid = s.countryid
GROUP BY c.countryid
),
tab_b AS (
SELECT c.countryid, COUNT (cc.cityid) city_num
FROM country c
LEFT JOIN state s ON c.countryid = s.countryid
LEFT JOIN city cc ON s.stateid = cc.stateid
GROUP BY c.countryid
)
SELECT a.countryid,
a.state_num,
b.city_num
FROM tab_a a JOIN tab_b b ON a.countryid=b.countryid

SQL query to find a record which has all matching records in another table

I have below 3 tables and I want to write a SQL query which will list the store present in all city: (here the result should be "Walmart")
Stores:
ID Name
1 Walmart
2 Target
3 Sears
Stores_City
ID Store_id City ID
1 1 10
2 1 20
3 2 10
4 1 30
City
ID Name
10 NewYork
20 Boston
30 Eagan
I am unable to find a query that works. Any help is appreciated!
select s.Name
from Stores s
inner join
(
select store_id, count(distinct city_id)
from stores_city
group by store_id
having count(distinct city_id) = (select count(*) from City)
) x
on x.store_id = s.id;
You can do it by grouping on store_id and checking for the count from stores table.
A straight join would work
Select distinct s.name from stores s inner join store _city SC on s.id=sc.id
Inner join city c on
Sc.city_id = c.id
Here is another way that will work:
select s.*
from stores s
where not exists (
select c.id
from city c
except
select sc.city_id
from stores_city sc
where sc.store_id = s.id
)
Try this:
SELECT
s.Name
FROM Stores s
WHERE NOT EXISTS (SELECT TOP 1
1
FROM City c
LEFT JOIN Stores_City sc
ON c.ID = sc.CityID
AND sc.Store_id = s.ID
WHERE sc.ID IS NULL)