Not unique table/alias? - sql

I get this error: Not unique table/alias: 'postcode'
"SELECT sub.city AS city, sub.postalcode AS postalcode FROM
(SELECT postcode.city AS city, customers.postalcode AS postalcode, COUNT(customers.postalcode) AS postcode_numbers
FROM orders, postcode
INNER JOIN customers ON orders.userID = customers.ID
INNER JOIN postcode ON customers.postalcode = postcode.city
GROUP BY customers.postalcode) sub
WHERE sub.postcode_numbers > 3";

Remove postcode table in the from statement
SELECT sub.city AS city, sub.postalcode AS postalcode FROM
(SELECT postcode.city AS city, customers.postalcode AS postalcode, COUNT(customers.postalcode) AS postcode_numbers
FROM orders
INNER JOIN customers ON orders.userID = customers.ID
INNER JOIN postcode ON customers.postalcode = postcode.city
GROUP BY customers.postalcode) sub
WHERE sub.postcode_numbers > 3

You have postcode in both your from clause and your second join clause. Remove it from the from clause and you should be OK:
SELECT sub.city AS city, sub.postalcode AS postalcode FROM
(SELECT postcode.city AS city, customers.postalcode AS postalcode, COUNT(customers.postalcode) AS postcode_numbers
FROM orders -- Removed postcode from here
INNER JOIN customers ON orders.userID = customers.ID
INNER JOIN postcode ON customers.postalcode = postcode.city
GROUP BY customers.postalcode) sub
WHERE sub.postcode_numbers > 3

You can write this as:
SELECT p.city, c.postalcode , COUNT(*) AS num_orders
FROM orders o JOIN
customers c
ON o.userID = c.ID JOIN
postcode p
ON c.postalcode = p.city
GROUP BY p.city, c.postalcode
HAVING COUNT(*) > 3;
It is unclear whether you want one row per city or per city/postalcode. This assumes the latter. If you want one row per city, remove postalcode from both the SELECT and the GROUP BY.
Notes:
Never use commas in the FROM clause. Always use proper, explicit, standard JOIN syntax. That is your specific problem.
Table aliases make the query easier to write and to read.
The unaggregated columns in the SELECT should match the GROUP BY keys.
A subquery is not necessary.

You are using postcode table in both FROM clause and and INNER JOIN clause, neither of which have an alias, when you do an INNER JOIN you don't need to have that table in the FROM clause, and other way around of course.
If you want to join the tables in FROM clause you would do something like this:
SELECT
sub.city AS city, sub.postalcode AS postalcode
FROM
(SELECT
postcode.city AS city, customers.postalcode AS postalcode,
COUNT(customers.postalcode) AS postcode_numbers
FROM
orders, postcode
INNER JOIN
customers ON orders.userID = customers.ID
--INNER JOIN postcode ON customers.postalcode = postcode.city
WHERE
postcode.city = customers.postalcode
GROUP BY
customers.postalcode) sub
WHERE
sub.postcode_numbers > 3;
So basically you would lose the INNER JOIN postcode... line
The other way to do this is to use only the INNER JOIN clause, which is my preferred way. To do this you only need to lose the postcode in FROM clause, like so:
SELECT
sub.city AS city, sub.postalcode AS postalcode
FROM
(SELECT
postcode.city AS city, customers.postalcode AS postalcode,
COUNT(customers.postalcode) AS postcode_numbers
FROM
orders
INNER JOIN
customers ON orders.userID = customers.ID
INNER JOIN
postcode ON customers.postalcode = postcode.city
GROUP BY
customers.postalcode) sub
WHERE
sub.postcode_numbers > 3;
Hope this helps!

Related

Why Oracle OFFSET and LIMIT is not working when using DISTINCT

I need to get clarified the below situation.
I have a city, country table and I need to validate this will some other tables and get the city country results ordered by the country. Here's my query for that
SELECT distinct
c.code as CITY ,
c.country as COUNTRY from location_info li
inner join someTable s on li.loc_id = s.some_id
inner join city c on s.city = c.code
ORDER BY c.country
And this provides the results as
Now when I use OFFSET and LIMIT values in the below query
SELECT distinct
c.code as CITY,
c.country as COUNTRY from location_info li
inner join someTable s on li.loc_id = s.some_id
inner join city c on s.city = c.code
ORDER BY c.country OFFSET 5 ROWS FETCH NEXT 5 ROWS ONLY.
I expect to get ADOR, ADPC, ADSJ, ADVD, ALV as the output.
Why is that and what I am missing here in this query.
When I do the following I get the expected outcome
SELECT CITY, COUNTRY FROM ( SELECT distinct
c.code as CITY,
c.country as COUNTRY from location_info li
inner join someTable s on li.loc_id = s.some_id
inner join city c on s.city = c.code
ORDER BY c.country ) OFFSET 5 ROWS FETCH NEXT 5 ROWS ONLY.
The issue is that the ORDER BY is not stable. What that means is that you have ties in the key values. So, running the query two times might result in different orderings.
This is easily fixed by including more keys in the order by so the order by keys uniquely identify each row:
select distinct c.code as CITY, c.country as COUNTRY
from location_info li join
someTable s
on li.loc_id = s.some_id join
city c
on s.city = c.code
order by c.country, c.code;

SQL join(INNER JOIN )

This part requires you to write a simple inner join of several tables.
Write a SQL statement that returns a data set with all airports in London. The data set must contain, for each airport, the name of the city, the country, the airport code and its latitude and longi-tude
My answer here:
SELECT City.name, Country.name, Airport.code, Airport.latitude,
Airport.longtitude
FROM City, Airport, Country
WHERE Country.id = City.Country
AND Airport.city = City.id
AND City.name = "London"
Am I right? Do I need to write the keywords like "INNER JOIN" or "ON" on my code?
This is ok.
SELECT City.name, Country.name, Airport.code, Airport.latitude, Airport.longtitude
FROM City, Airport, Country
WHERE
Country.id = City.Country
AND Airport.city = City.id
AND City.name = "London"
But can also be write like this
SELECT City.name, Country.name, Airport.code, Airport.latitude, Airport.longtitude
FROM
City
inner join Country ON Country.id = City.Country
inner join Airport ON Airport.city = City.id
WHERE
City.name = "London"
Given that the question asks for a 'a simple inner join', then yes, you'll need to use those keywords! INNER JOIN is used to link tables that have matching columns. For example, if one table contains details about a city, another table can refer to it via its ID column, and a query using INNER JOIN can retrieve details from both. If the city details change, they only need to be changed in one table.
In your example, the query would look something like this:
SELECT
c.name,
cty.name,
ap.code,
ap.latitude,
ap.longtitude
FROM
Airport ap
INNER JOIN City c ON ap.city = c.id
INNER JOIN Country cty ON c.Country = cty.id
WHERE
c.name = "London"
SELECT City.name, Country.name, Airport.code, Airport.latitude,
Airport.longtitude
from Airport
inner join city on Airport.city = City.id
inner join Country ON Country.id = City.Country
where
city.name='London'

Nested 'Where'?

I have a table named Actor, with only a column for City (CityId). I want to return the number of actors in a particular State (StateId). The catch however is that I have separate tables for City, County, and finally State (City has CountyId, County has StateId). How do I this in a T-SQL query?
I have a solution that involves nested Select statements, something like:
SELECT COUNT(1)
FROM Actor a
WHERE a.CityId IN
(SELECT CityId FROM City WHERE CountyId IN...)
...but is there a more efficient way to do this? Thanks
You can use this query to get your output
----------------------------------------------------------
SELECT COUNT(ActorId)
FROM Actor a
INNER JOIN City c ON a.cityId = c.cityId
INNER JOIN Country con ON c.countryId = con.countryId
INNER JOIN STATE s ON con.stateId = s.stateId
GROUP BY s.stateId
Use JOINS to query your data.
I am using INNER JOIN here.
Assuming that you have CountryId in your City Table, You can do it following way.
In case you don't have countryId in your City Table you have to apply one more INNER JOIN on State Table.
SELECT COUNT(1) FROM Actor a INNER JOIN
City b ON a.CityId = b.CityId
WHERE b.CountryId IN (...)
You can easily put the JOINS across different table that you have and then use the Group By clause to find out the total number of actors from specific state.
I have used the column name on the basis of my wild guess, you can change them with the original name that you have in your database.
SELECT StateId,
Count(ActorId) AS Total
FROM ACTOR
INNER JOIN City ON Actor.CityId = City.CityId
INNER JOIN County ON County.CountyId = City.CountyId
INNER JOIN State ON State.StateId = County.StateId
GROUP BY State.StateId
Assuming the relation names, you can do something like this with joins:
select s.ID, s.Name, count(*)
from Actors a
inner join Cities c on c.ID = a.CityID
inner join County cn on cn.ID = c.CountyID
inner join State s on s.ID = cn.StateID
group by s.ID, s.Name
If you only need the StateId you don't even need to join with states, this will do:
select cn.StateID, count(*)
from Actors a
inner join Cities c on c.ID = a.CityID
inner join County cn on cn.ID = c.CountyID
group by cn.StateID

SQL query - IS NULL

Tables:
Country
-------
PK CountryID
Name
City
-------
PK CityID
FK CountryID
Name
Airport
--------
PK AirportID
FK CityID
Name
My task is to select names of countries that have no airport.
I can imagine only one solution with EXCEPT (or MINUS)
SELECT Country.Name
FROM Country EXCEPT (SELECT DISTINCT Country.Name FROM Country, City, Airport
WHERE City.CountryID = Country.CountryID AND Airport.CityID = City.CityID);
But is it possible not to use EXCEPT but something like IS NULL?
SELECT cn.CountryID
FROM Country cn
LEFT JOIN City ct ON cn.CountryID = ct.CountryID
LEFT JOIN Airport ar on ar.CityID=ct.CityID
WHERE ar.AirportID is null
If you need to make this query with IS NULL try following query:
SQLFiddle demo
select ct.CountryId,max(ct.Name) from Country ct
left join City c on ct.CountryId=c.CountryId
left join Airport a on a.CityId=c.CityID
group by ct.CountryId
HAVING max(a.AirportID) IS NULL
You can use this, but it's basically the same thing you have with different syntax.
SELECT Country.Name
FROM Country
Where Country.Name Not IN
(
SELECT DISTINCT Country.Name FROM Country, City, Airport
WHERE City.CountryID = Country.CountryID AND Airport.CityID = City.CityID
);

SQL Query Adding All Customers even if they don't have any sales

Below is my relatively simple sales query but I want it to pick up all of my dealers, not just the dealers that have sales. Is this possible?
SELECT dbo.tblDealer.DealerID, Firstname, LastName,
SUM(dbo.tblOrderDetail.PSVAmount) AS "PSV",
SUM(dbo.tblOrderDetail.UplineVolume) AS "Upline",
SUM(dbo.tblOrderDetail.LineTotal) AS "Product Total"
FROM tblOrderDetail
inner join tblOrder
on dbo.tblOrderDetail.OrderID = dbo.tblOrder.OrderID
inner join tblDealership on dbo.tblOrder.DealershipID = dbo.tblDealership.DealershipID
inner join tblDealer on dbo.tblDealership.DealerID = dbo.tblDealer.DealerID
where orderDate between '3/01/12' and '3/21/12 23:59:59'
and dbo.tbldealer.active = -1
GROUP BY dbo.tblDealer.DealerID, Firstname, LastName
You should change the order of your joins, and do an outer join instead of an inner join:
SELECT dbo.tblDealer.DealerID, Firstname, LastName,
SUM(dbo.tblOrderDetail.PSVAmount) AS "PSV",
SUM(dbo.tblOrderDetail.UplineVolume) AS "Upline",
SUM(dbo.tblOrderDetail.LineTotal) AS "Product Total"
FROM tblDealer
inner join tblDealership
on dbo.tblDealership.DealerID = dbo.tblDealer.DealerID
left join tblOrder
on dbo.tblOrderDetail.OrderID = dbo.tblOrder.OrderID AND orderDate between '3/01/12' and '3/21/12 23:59:59'
left join tblOrder
on dbo.tblOrderDetail.OrderID = dbo.tblOrder.OrderID
where dbo.tbldealer.active = -1
GROUP BY dbo.tblDealer.DealerID, Firstname, LastName