UNION vs. JOIN, b and c not defined? (sqlite3) - sql

select city, prov, a, b, c from (
select count(city) as a, city, prov from locations left outer join rides on src=lcode
group by city
union
select count(city) as b, city, prov from locations left outer join rides on dst=lcode
group by city
union
select count(city) as c, city, prov from locations l left outer join enroute e on l.lcode=e.lcode
group by city
) group by city;
So I got an error saying "no such column: b" (and also column c). Is it possible to solve this without changing a lot of this query?

Your subquery is returning three columns, a, city, and prov. That is, for a union/union all query, the column names come from the first subquery. There is no b or c.
Presumably, you want some sort of JOIN, not UNION ALL. However, your question does not explain what you are trying to do. And it doesn't have sample data or desired results. So, it is really hard to say what you actually want.
It strikes me that you actually want:
select city, prov, sum(a), sum(b), sum(c)
from ((select city, prov, count(city) as a, null as b, null as c
from locations left outer join
rides on src = lcode
group by city
) union all
(select city, prov, null, count(city), 0
from locations left outer join
rides
on dst = lcode
group by city
) union all
(select city, prov, null, null, count(city)
from locations l left outer join
enroute e
on l.lcode = e.lcode
group by city
)
) abc
group by city;

The expressions that are not encapsulated within an aggregate function and must be included in the GROUP BY clause. For Unions, all of the select statements in those unions must have the same column names.
Below would do the required tasks.
select * from (
select count(city) as cityCount, prov from locations left outer join rides on src=lcode
group by prov
union
select count(city) as cityCount, prov from locations left outer join rides on dst=lcode
group by prov
union
select count(city) as cityCount,prov from locations l left outer join enroute e on l.lcode=e.lcode
group by prov
);
Doesn't require an additional groupby for Outside subquery. It will already be grouped by provinces of locations.

Related

Selecting rows with the most repeated values at specific column

Problem in general words: I need to select value from one table referenced to the most repeated values in another table.
Tables have this structure:
screenshot
screenshot2
The question is to find country which has the most results from sportsmen related to it.
First, INNER JOIN tables to have relation between result and country
SELECT competition_id, country FROM result
INNER JOIN sportsman USING (sportsman_id);
Then, I count how much time each country appear
SELECT country, COUNT(country) AS highest_participation
FROM (SELECT competition_id, country FROM result
INNER JOIN sportsman USING (sportsman_id))
GROUP BY country
;
And got this screenshot3
Now it feels like I'm one step away from solution ))
I guess it's possible with one more SELECT FROM (SELECT ...) and MAX() but I can't wrap it up?
ps:
I did it with doubling the query like this but I feel like it's so inefficient if there are millions of rows.
SELECT country
FROM (SELECT country, COUNT(country) AS highest_participation
FROM (SELECT competition_id, country FROM result
INNER JOIN sportsman USING (sportsman_id)
) GROUP BY country
)
WHERE highest_participation = (SELECT MAX(highest_participation)
FROM (SELECT country, COUNT(country) AS highest_participation
FROM (SELECT competition_id, country FROM result
INNER JOIN sportsman USING (sportsman_id)
) GROUP BY country
))
Also I did it with a view
CREATE VIEW temp AS
SELECT country as country_with_most_participations, COUNT(country) as country_participate_in_#_comp
FROM(
SELECT country, competition_id FROM result
INNER JOIN sportsman USING(sportsman_id)
)
GROUP BY country;
SELECT country_with_most_participations FROM temp
WHERE country_participate_in_#_comp = (SELECT MAX(country_participate_in_#_comp) FROM temp);
But not sure if it's easiest way.
If I understand this correctly you want to rank the countries per competition count and show the highest ranking country (or countries) with their count. I suggest you use RANK for the ranking.
select country, competition_count
from
(
select
s.country,
count(*) as competition_count,
rank() over (order by count(*) desc) as rn
from sportsman s
inner join result r using (sportsman_id)
group by s.country
) ranked_by_count
where rn = 1
order by country;
If the order of the result rows doesn't matter, you can shorten this to:
select s.country, count(*) as competition_count
from sportsman s
inner join result r using (sportsman_id)
group by s.country
order by count(*) desc
fetch first rows with ties;
You seem to be overcomplicating this. Starting from your existing join query, you can aggregate, order the results and keep the top row(s) only.
select s.country, count(*) cnt
from sportsman s
inner join result r using (sportsman_id)
group by s.country
order by cnt desc
fetch first 1 row with ties
Note that this allows top ties, if any.
SELECT country
FROM (SELECT country, COUNT(country) AS highest_participation
FROM (SELECT competition_id, country FROM result
INNER JOIN sportsman USING (sportsman_id)
) GROUP BY country
order by 2 desc
)
where rownum=1

Count the repeats of foreign key of two tables

I have two tables Countries( id, country) and Cities (id, city, countryId ) I want to select countries and to show how much cities AS locations .
I tried this :
SELECT countryid, COUNT(*) AS locations
FROM Cities
GROUP BY countryid
but it shows me countryid instead of country
You need to join the tables as follows:
select c.country, count(*) as locations
from Country c
inner join Cities ci
on c.id = ci.countryId
group by c.id, c.country
I also included the country in the group by since it appears in the select clause

SQL JOIN returns more records than expected

I have the table:
Country city population
------------------------
Israel RG 100
Israel TA 300
US NY 900
US SF 700
In order to get for each country the max population I am running the below query:
select Country, max(population) as maxPopulation
from A
group by Country
I want to get full output:
Country city population
-----------------------
Israel TA 300
US NY 900
In order to do it I need to join on the full table - please correct me if I am wrong.
select A.Country, A.city, A.population
from A
right join
(select Country, max(population) as maxPopulation
from A
group by Country) temp on temp.Country = A.Country
This returns all the 4 records... instead of 2...
You can use correlated subquery :
select a.*
from a
where population = (select max(a1.population) from a a1 where a1.Country = a.Country);
For your JOIN query version, you need one more condition that is . . . and temp.maxPopulation = A.Population & why you need right join here only inner join is sufficient :
select a.*
from a inner join
(select Country, max(population) as maxPopulation
from a
group by Country
) temp
on temp.Country = a.Country and temp.maxPopulation = a.population;
I would use a standard CTE:
with
x as (
select country, max(population) as pop from A group by country
)
select A.*
from A
join x on x.country = A.country and x.pop = A.population
A [desirable?] side effect of this query, is that if there are multiple cities with the same max population it will show them all.

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 MAX() value across 2 or more queries

This seems like a basic action in SQL, but it has me stumped.
I have about 2 different subqueries, each grouped by LOCATION_ID that contain a date column. For example, one query includes a listing of WORKORDER records while another query pulls records from the NOTE table. Both of these queries includes a join to the LOCATION table allowing me to group by LOCATION_ID.
My goal is to pull the latest date of contact at that particular location and that can be in the form of a workorder, note date, followup date, etc. which are stored in different tables. So ideally I would have a query grouped by LOCATION_ID that shows the latest date of contact for that location.
I would post SQL but I don't have anything that is currently working for me. Any ideas on how to approach this type of scenario?
Thanks!
SELECT
L.LOCATION_ID, Max(MaxDate)
FROM
LOCATION AS L
LEFT JOIN
(SELECT
LOCATION_ID, Max(dbo.LeadNote.NoteDate) AS MaxDate
FROM
LeadNote
INNER JOIN
LOCATION ON LeadNote.LOCATION_ID = LOCATION.LOCATION_ID
GROUP BY
LOCATION_ID) T1 ON L.LOCATION_ID = T1.CONTACTLOCATION_LOCATION_ID
LEFT JOIN
(SELECT
LOCATION_ID, Max(dbo.WORKORDER.WORKORDER_DATECREATED) AS MaxDate
FROM
WORKORDER
INNER JOIN
LOCATION ON LOCATION_ID = WORKORDER_LOCATION_ID
GROUP BY
LOCATION_ID) T2 ON L.LOCATION_ID = T2.CONTACTLOCATION_LOCATION_ID`
Perhaps you could try using UNION to get a single sql result, then wrap it and give it an alias, and then apply a MAX on the field you wish, which both queries return. Keep in mind that to use UNION both queries must return the same set of field names.
Ex:
Query A:
Select a, b, c from T1 where....
Query B:
Select a, f, e from T2 where...
you would have:
SELECT MAX(e)
FROM
(
(Select a, b, c, NULL as f, NULL as e from T1 where....)
UNION
(Select a, NULL as b, NULL as c, f, e from T2 where...)
) t
If you need to use a join you can use a case statement to fetch the larger date.
SELECT
L.LOCATION_ID,
(CASE WHEN(T2.MaxDate IS NULL OR T1.MaxDate > T2.MaxDate)
THEN T1.MaxDate
ELSE T2.MaxDate
END) MaxDate
...
Try:
SELECT
L.LOCATION_ID, Max(MaxDate)
FROM
(
(
SELECT
LOCATION_ID, Max(LeadNote.NoteDate) AS MaxDate
FROM
LeadNote
JOIN
LOCATION
ON
LeadNote.LOCATION_ID = LOCATION.LOCATION_ID
GROUP BY
LOCATION_ID
)
UNION
(
SELECT
LOCATION_ID, Max(WORKORDER.WORKORDER_DATECREATED) AS MaxDate
FROM
WORKORDER
JOIN
LOCATION ON LOCATION_ID = WORKORDER_LOCATION_ID
GROUP BY
LOCATION_ID
)
)
It may need a little tweaking...but kudos to the comment by #DrCopyPaste if this works :)
You can do this with a simple join and a case statement:
SELECT
L.LOCATION_ID,
CASE WHEN(Max(LeadNote.NoteDate) IS NULL OR Max(LeadNote.NoteDate) > Max(WORKORDER.WORKORDER_DATECREATED)
THEN Max(LeadNote.NoteDate)
ELSE Max(WORKORDER.WORKORDER_DATECREATED) end AS maxDate
FROM
LOCATION AS L
LEFT JOIN LeadNote ON LeadNote.LOCATION_ID = LOCATION.LOCATION_ID
LEFT JOIN WORKORDER ON L.LOCATION_ID = WORKORDER_LOCATION_ID
GROUP BY L.LOCATION_ID