Suggestion of a simple SQL query - sql

I have the following table:
state product_a product_b final_score
FL Apple Açai Berries 9
FL Apricot Banana 15
FL Avocado Coconut 5
FL Bilberry Apricot 17
FL Blackcurrant Apricot 6
FL Blackcurrant Boysenberry 12
FL Blueberry Avocado 11
FL Blueberry Cantaloupe 6
FL Cantaloupe Coconut 1
FL Currant Blackcurrant 5
FL Cherry Currant 10
FL Cherimoya Cherry 6
FL Cherimoya Date 14
FL Cloudberry Blueberry 16
FL Coconut Apricot 14
FL Cranberry Damson 1
FL Date Banana 5
NY Apricot Blackcurrant 5
NY Apricot Dragonfruit 15
NY Avocado Cherimoya 16
NY Avocado Coconut 18
NY Banana Damson 14
NY Bilberry Apricot 16
NY Bilberry Avocado 1
NY Blackberry Blackcurrant 20
NY Blackberry Cherimoya 12
NY Blackcurrant Damson 19
Based on "state" and "product_A" I need to return "product_B" with the highest "final_score".
For instance, if I check for NY "state", "product_A" Blackberry, I want my query to return Blackcurrant.
For instance, I used the following query:
select product_b from PRODUCTSUGGESTION a,
(select max(final_score) maxscore from PRODUCTSUGGESTION
where product_A like '%Blackcurrant%' and state like 'FL') r
where r.maxscore=final_score and product_A like '%Blackcurrant%' and state like 'FL'
The output would be: Boysenberry
The query I presented above gives me the wanted output. However, I know that joins increase the query complexity. Could anyone suggest another way of doing it with a simpler query?

Seems like this is too simple to me, but here you go:
SELECT product_b FROM PRODUCTSUGGESTION
WHERE state = 'FL' AND product_a = 'Blackcurrant'
ORDER by final_score DESC FETCH FIRST 1 ROW ONLY

You need calculate the maxScore first. Then join both tables to get the name.
SQL Fiddle Demo
This use sql server cte, MySql need inner select instead.
WITH maxScore as (
SELECT state, product_a, max(final_score) as final_score
FROM Table1
GROUP BY state, product_a
)
SELECT t.*, m.final_score
FROM Table1 t
inner join maxScore m
on t.state = m.state
and t.product_a = m.product_a
and t.final_score = m.final_score

Related

How to get the list of people who do NOT have citizenship of country X in SQL

I have the 3 following tables
People
Id
Name
Age
1
Bob
23
2
John
25
3
Fred
37
4
Avery
42
Citizenship
Person_ID
Country_ID
1
2
1
1
2
1
2
5
3
2
3
6
4
3
4
4
Country
Country_ID
Country_Name
Capital_City
1
UK
London
2
France
Paris
3
Canada
Ottawa
4
Australia
Canberra
5
Germany
Berlin
6
Russia
Moscow
The goal here is to find all people who do NOT have French citizenship. My initial query was as follows
SELECT p.name
FROM People p
LEFT JOIN Citizenship ct
ON p.id = ct.person_id
LEFT JOIN Country c
ON ct.country_id = c.country_id
WHERE c.country_name != 'France';
However, the result doesn't seem to be correct. What condition am I missing in this query?

looking for values from another table where they do not exist in a given group

I have two tables:
SHOPPING
date
id_customer
id_shop
id_fruit
28.03.2018
7423
123
1
13.02.2019
8408
354
1
28.03.2019
7767
123
9
13.02.2020
8543
472
7
28.03.2020
8640
346
9
13.02.2021
7375
323
9
28.03.2021
7474
323
8
13.02.2022
7476
499
1
28.03.2022
7299
123
4
13.02.2023
8879
281
2
28.03.2023
8353
452
1
13.02.2024
8608
499
6
28.03.2024
8867
318
1
13.02.2025
7997
499
6
28.03.2025
7715
499
4
13.02.2026
7673
441
7
FRUITS
id_fruit
name
1
apple
2
pear
3
grape
4
banana
5
plum
6
melon
7
watermelon
8
orange
9
pineapple
I would like to find fruits that have never been bought in a specific id_shop
I tried with this:
SELECT
s.idshop,
s.id_fruit ,
f.name
FROM
shopping s
LEFT JOIN fruit f ON f.id_fruit = s.id_fruit
WHERE NOT EXISTS (
SELECT *
FROM
fruit f1
WHERE f1.id_fruit = s.id_fruit
)
but it does not work...
Yes, you need an OUTER JOIN, but that should be RIGHT JOIN along with NULL values picked from shopping table after join applied, considering your current query such as
SELECT f.*
FROM shopping s
RIGHT JOIN fruit f
ON f.id_fruit = s.id_fruit
WHERE s.id_fruit IS NULL
Demo

Join multiple tables and pick results from most recent table

I have 4 tables. I want all the rows and cols from my first table tbl_2021 and only those data which are not in tbl_2021 but present in the the rest 3 tables, but based on one condition
if there id exist in tbl_2020, tbl_2019 and in tbl_2018 then i need the id and it's details from the most recent table that is tbl_2020.
if an id is across 2019 and 2018 table, then i need the data from 2019 so on like that.If in 2020 and 018 then 020 and so on
if the same is across 2021,2020,2019 and 2018 then the data from 2021 is selected.
And - I'm hail from a shell scripting background, and i've just started with sql. so if any noble mind could tell me the approach or what i should do to get these pieces together would mean more than happiness to me. Thank you
tbl_2021
id
name
addr
location
country
contintent
gdp
123
rob
dware
texas
us
us
8
456
lilly
gwood
london
uk
uk
5
670
rick
utown
newyrok
us
us
8
490
zang
kcity
hk
hongkong
hongkong
6
tbl_020
id
location
name
999
ger
roger
888
bel
leslie
670
us
marie
tbl_019
id
location
name
data
network
999
uk
roger
xx
na
555
rus
vladmir
ux
na
879
us
marie
xx
ua
481
cn
kim
tbl_018
id
location
name
data
network
823
uk
roger
xx
na
555
rus
vladmir
ux
na
879
us
maria
xx
ua
670
us
marie
xy
uy
888
in
raj
xx
jo
output:
id
name
addr
location
country
contintent
gdp
123
rob
dware
texas
us
us
8
456
lilly
gwood
london
uk
uk
5
670
rick
utown
newyrok
us
us
8
490
zang
kcity
hk
hongkong
hongkong
6
999
roger
ger
888
leslie
bel
555
vladmir
rus
879
marie
us
481
kim
cn
823
roger
uk
First, you should fix your data model. It is not a good idea to store such data in separate tables. Instead, you should store in a single table with a year column.
Second, I think you can solve your problem using full join, but it is a little tricky:
select coalesce(t21.id, t20.id, t19.id, t18.id) as id,
coalesce(t21.name, t20.name, t19.name, t18.name) as name,
t21.addr,
. . .
from tbl_2021 t21 full join
tbl_2020 t20
on t21.id = t20.id full join
tbl_2019 t19
on t19.id = coalesce(t21.id, t20.id) full join
tbl_2018 t18
on t18.id = coalesce(t21.id, t20.id, t19.id);
You need to carefully figure out how the columns should be pulled from the different tables.
First you can union all the data from four tables with union all. Then with row_number() we need to serialized rows for each id from higher to lower. Finally select one row for each id with highest year .
with cte as
(
select id,name addr ,location ,country, contintent,data,network, row_number()over (partition by id order by sl ) rn from
(
select id,name ,addr ,location , country, contintent,data,network, 1 sl from tbl_21
union all
select id,name ,'' addr ,location ,'' country,'' contintent, data, network, 2 sl from tbl_20
union all
select id,name ,'' addr ,location ,'' country,'' contintent, data,network, 3 sl from tbl_19
union all
select id,name ,'' addr ,location ,'' country,'' contintent, data,network, 4 sl from tbl_18
)t
)
select id,name ,addr ,location ,country, contintent,data,network from cte where rn=1

Get data from string of specific values SQL

I'm rather new at SQL programming, and still struggling with the basics. I need to extract some specific rows, from a specified string of IDs.
ID Product City
1 Apple London
2 Banana Berlin
3 Orange Berlin
4 Orange Paris
5 Apple Paris
6 Banana Copenhagen
7 Banana Copenhagen
8 Banana London
9 Apple Paris
10 Orange London
11 Apple Berlin
12 Apple Copenhagen
13 Apple Paris
If I need to select ID=1,2,5,6,10,11,13 how do I extract these specific rows from the database?
I'm using SQLite.
Thanks in advance.
You should use the in clause
select * from your_table
where id in (1,2,5,6,10,11,13)

Retrieve top 48 unique records from database based on a sorted Field

I have database table that I am after some SQL for (Which is defeating me so far!)
Imagine there are 192 Athletic Clubs who all take part in 12 Track Meets per season.
So that is 2304 individual performances per season (for example in the 100Metres)
I would like to find the top 48 (unique) individual performances from the table, these 48 athletes are then going to take part in the end of season World Championships.
So imagine the 2 fastest times are both set by "John Smith", but he can only be entered once in the world champs. So i would then look for the next fastest time not set by "John Smith"... so on and so until I have 48 unique athletes..
hope that makes sense.
thanks in advance if anyone can help
PS
I did have a nice screen shot created that would explain it much better. but as a newish user i cannot post images.
I'll try a copy and paste version instead...
ID AthleteName AthleteID Time
1 Josh Lewis 3 11.99
2 Joe Dundee 4 11.31
3 Mark Danes 5 13.44
4 Josh Lewis 3 13.12
5 John Smith 1 11.12
6 John Smith 1 12.18
7 John Smith 1 11.22
8 Adam Bennett 6 11.33
9 Ronny Bower 7 12.88
10 John Smith 1 13.49
11 Adam Bennett 6 12.55
12 Mark Danes 5 12.12
13 Carl Tompkins 2 13.11
14 Joe Dundee 4 11.28
15 Ronny Bower 7 12.14
16 Carl Tompkin 2 11.88
17 Nigel Downs 8 14.14
18 Nigel Downs 8 12.19
Top 4 unique individual performances
1 John Smith 1 11.12
3 Joe Dundee 4 11.28
5 Adam Bennett 6 11.33
6 Carl Tompkins 2 11.88
Basically something like this:
select top 48 *
from (
select athleteId,min(time) as bestTime
from theRaces
where raceId = '123' -- e.g., 123=100 meters
group by athleteId
) x
order by bestTime
try this --
select x.ID, x.AthleteName , x.AthleteID , x.Time
(
select rownum tr_count,v.AthleteID AthleteID, v.AthleteName AthleteName, v.Time Time,v.id id
from
(
select
tr1.AthleteName AthleteName, tr1.Time time,min(tr1.id) id, tr1.AthleteID AthleteID
from theRaces tr1
where time =
(select min(time) from theRaces tr2 where tr2.athleteId = tr1.athleteId)
group by tr1.AthleteName, tr1.AthleteID, tr1.Time
having tr1.Time = ( select min(tr2.time) from theRaces tr2 where tr1.AthleteID =tr2.AthleteID)
order by tr1.time
) v
) x
where x.tr_count < 48