Why Oracle OFFSET and LIMIT is not working when using DISTINCT - sql

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;

Related

SQLite: How does order of execution work given a CASE WHEN subquery?

The below code is part of a working SQLite pull. Can someone explain how the WHEN section works? It leverages a subquery in the parenthesis. I thought that a subquery would execute prior to the outer query. In that case how can country = c.country work? Doesn't c.country only exist once the outer query executes?
WITH country_or_other AS
(
SELECT
CASE
WHEN (
SELECT count(*)
FROM customer
where country = c.country
) = 1 THEN "Other"
ELSE c.country
END AS country,
c.customer_id,
il.*
FROM invoice_line il
INNER JOIN invoice i ON i.invoice_id = il.invoice_id
INNER JOIN customer c ON c.customer_id = i.customer_id
)
In every row of your query there is the column c.country from the joined table customer.
So for every row of your query, this query:
SELECT count(*)
FROM customer
where country = c.country
is executed and returns the number of rows in the table customer where the column country is equal to the value of c.country.
This number is compared to 1 and the CASE expression returns either 'Other' or the value of c.country.
This is how I would write this code:
WITH country_or_other AS
(
SELECT
CASE
WHEN t.counter = 1 THEN "Other"
ELSE c.country
END AS country,
c.customer_id,
il.*
FROM invoice_line il
INNER JOIN invoice i ON i.invoice_id = il.invoice_id
INNER JOIN customer c ON c.customer_id = i.customer_id
INNER JOIN (SELECT country, count(*) counter FROM customer GROUP BY country) t ON t.country = c.country
)
I assume the column country in the table customer is not NULL.
You have a correlated subquery. Conceptually, the subquery is run for every row generated by the outer query. Each run has a different value for the external reference.
However, a correlated subquery is not needed:
SELECT (CASE WHEN COUNT(*) OVER (PARTITION BY c.country) = 1
THEN 'Other'
ELSE c.country
END) AS country,
c.customer_id,
il.*
FROM invoice_line il JOIN
invoice i
ON i.invoice_id = il.invoice_id JOIN
customer c
ON c.customer_id = i.customer_id

Create a list of every country where we have customers but not suppliers

So I have to make a query where we have only customers in a country by no suppliers
Select Distinct s.ContactName as ShippersName, s.Country as Location,
c.ContactName as CustomersName, c.Country as Location
From Suppliers s
Join Customers c
On s.Country != c.Country
Where c.country not in (s. country)
order by c.country
I got the results, but its giving me where they aren't equal...
I just want the country that only has customers. Is there like a special keyword?
You can use NOT EXISTS and a correlated subquery.
SELECT DISTINCT c.country
FROM customers c
WHERE NOT EXISTS (SELECT *
FROM suppliers s
WHERE s.country = c.country);
If you are trying to get customer records where the country is not in the supplier table, then the first columns of your result set can be removed since they will always be NULL:
SELECT DISTINCT c.ContactName AS CustomersName, c.Country AS Location
FROM customers c
LEFT JOIN Suppliers s
ON c.Country = s.Country
WHERE s.country IS NULL
ORDER BY c.country

GROUP BY with JOIN not giving correct result

How can I find the number of persons from each country
Person table
country_id, fName, lName
Countries table
country_id, country_name
I can find the number of persons from each country with their country IDs, using the below SQL statement
select
p.country_id, COUNT(p.country_id) as [Count]
from
persons p
GROUP BY
p.country_id
But what if I want to fetch country_name instead of country_id?
I tried this so far but it does not work as expected so I am missing something here.
select
c.country_name, COUNT(p.country_id) as [Count]
from
persons p INNER JOIN countries c ON p.country_id = c.country_id
GROUP BY
p.country_id
SQL Server 2000
GROUP BY the columns in the SELECT:
SELECT c.country_name, COUNT(p.country_id) as [Count]
FROM persons p INNER JOIN
countries c
ON p.country_id = c.country_id
GROUP BY c.country_name;
Notes:
Under some circumstances, you would want to include both the id and the name in the GROUP BY -- this would happen if two countries had the same name.
You can use COUNT(*) instead of COUNT(p.country_id). There is no problem counting rows instead of NULL-values.
If you wanted all countries, even those without people, then you would use an outer JOIN:
SELECT c.country_name, COUNT(p.country_id) as [Count]
FROM countries c LEFT JOIN
persons p
ON p.country_id = c.country_id
GROUP BY c.country_name;
You need to mention the column_name which is mentioned in select .
select
c.country_name, COUNT(p.country_id) as [Count]
from
persons p INNER JOIN countries c ON p.country_id = c.country_id
GROUP BY
c.country_name
You could use group by c.country_name .. the column you have in select and you use for refer the group by
select c.country_name, COUNT(p.country_id) as [Count]
from persons p INNER JOIN countries c ON p.country_id = c.country_id
GROUP BY c.country_name
The SQL statement is correct. There was some data corruption in the database due to which the results were not returned correctly.

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

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