SQL selecting minimum value in a sub query when exact value is unknown - sql

I have an SQL query that is meant to select a list of things from different tables using a subquery. I am meant to find those things with the lowest value in a particular column.
This is the query that i currently have. I know the minimum rate is 350 but i cant use it in my query. Any effort to change it to MIN(rate) has been unsuccessful.
SELECT DISTINCT name
FROM table1 NATURAL JOIN table2
WHERE table2.code = (SELECT Code FROM rates WHERE rate = '100')
How do i change that subquery to find the minimum rate?

Most general way to do this would be
select distinct name
from table1 natural join table2
where
table2.code in
(
select t.Code
from rates as t
where t.rate in (select min(r.rate) from rates as r)
)
if you have windowed functions, you can use rank() function:
...
where
table2.code in
(
select t.Code
from (
select r.Code, rank() over(order by r.rate) as rn
from rates as r
) as t
where t.rn = 1
)
in SQL Server you can use top ... with ties syntax:
...
where
table2.code in
(
select top 1 with ties r.Code
from rates as r
order by r.rate
)

SELECT DISTINCT name
FROM table1 NATURAL JOIN table2
WHERE table2.code =
(SELECT CODE FROM RATE WHERE RATE=(SELECT MIN(RATE) FROM RATE))
Considering you are expecting only one record of minimum value.

try this,
WHERE table2.code = (SELECT Code FROM rates ORDER BY rate LIMIT 1)

Related

SQL MAX funtion where not all atributes are in the group by

So my current problem is that I have two tables that look like this:
table1(name, num_patient, quant, inst)
table2(inst_name, num_region)
Where I want to find the patient with max quantity per region.
I first had the idea of doing something like this:
SELECT num_region, num_patient, MAX(quant)
FROM
(SELECT num_patient, quant, num_region
FROM table1
INNER JOIN table2
ON table1.inst = table2.inst_name) AS joined_tables
GROUP BY num_region;
But this doesn't work since either num_patient has to be on the GROUP BY (and this way it doesn't return the max value by region anymore) or I have to remove it from the SELECT (also doesn't work because I need the name of each patient). I have tried to fix my issue with a WHERE quant = MAX() statement but couldn't get it to work. Is there any workaround to this?
Use DISTINCT ON:
SELECT DISTINCT ON (num_region), num_patient, quant, num_region
FROM table1 t1 JOIN
table2 t2
ON t1.inst = t2.inst_name
ORDER BY num_region, quant DESC;
DISTINCT ON is a convenient Postgres extension. It returns one row per keys specified in the SELECT, based on the ordering in the ORDER BY.
Being an extension, not all databases support this functionality -- even databases derived from Postgres. The traditional method would use ROW_NUMBER():
SELECT t.*
FROM (SELECT num_patient, quant, num_region,
ROW_NUMBER() OVER (PARTITION BY num_region ORDER BY quant DESC) as seqnum
FROM table1 t1 JOIN
table2 t2
ON t1.inst = t2.inst_name
) t
WHERE seqnum = 1;
This is a duplicate of the DISTINCT ON question I linked.
SELECT distinct on (num_region) num_patient, quant, num_region
FROM table1
INNER JOIN table2
ON table1.inst = table2.inst_name
ORDER BY num_region, quant desc

Postgresql - Group By

I have a simple groupby scenario. Below is the output of the query.
Query is:
select target_date, type, count(*) from table_name group by target_date, type
The query and output is perfectly good.
My problem is I am using this in Grafana for plotting. That is Grafana with postgres as backend.
What happens is since "type2" category is missed on 01-10-2020 and 03-10-2020, type2 category never gets plotted (side to side bar plot) at all. Though "type2" is present in other days.
It is expecting some thing like
So whenever a category is missed in a date, we need a count with 0 value.
Need to handle this in query, as the source data cannot be modified.
Any help here is appreciated.
You need to create a list of all the target_date/type combinations. That can be done with a CROSS JOIN of two DISTINCT selects of target_date and type. This list can beLEFT JOINed to table_name to get counts for each combination:
SELECT dates.target_date, types.type, COUNT(t.target_date)
FROM (
SELECT DISTINCT target_date
FROM table_name
) dates
CROSS JOIN (
SELECT DISTINCT type
FROM table_name
) types
LEFT JOIN table_name t ON t.target_date = dates.target_date AND t.type = types.type
GROUP BY dates.target_date, types.type
ORDER BY dates.target_date, types.type
Demo on dbfiddle
You may use a calendar table approach here:
SELECT
t1.target_date,
t2.type,
COUNT(t3.target_date) AS count
FROM (SELECT DISTINCT target_date FROM yourTable) t1
CROSS JOIN (SELECT DISTINCT type FROM yourTable) t2
LEFT JOIN yourTable t3
ON t3.target_date = t1.target_date AND
t3.type = t2.type
GROUP BY
t1.target_date,
t2.type
ORDER BY
t1.target_date,
t2.type;
The idea here is to cross join subqueries finding all distinct target dates and types, to generate a starting point for the query. Then, we left join this intermediate table to your actual table, and find the counts for each date and type.
select t.target_date, tmp.type, sum(case when t.type = tmp.type then 1 else 0 end)
from your_table t
cross join (select distinct type from your_table) tmp
group by t.target_date, tmp.type
Demo

SQL Server query showing most recent distinct data

I am trying to build a SQL query to recover only the most young record of a table (it has a Timestamp column already) where the item by which I want to filter appears several times, as shown in my table example:
.
Basically, I have a table1 with Id, Millis, fkName and Price, and a table2 with Id and Name.
In table1, items can appear several times with the same fkName.
What I need to achieve is building up a single query where I can list the last record for every fkName, so that I can get the most actual price for every item.
What I have tried so far is a query with
SELECT DISTINCT [table1].[Millis], [table2].[Name], [table1].[Price]
FROM [table1]
JOIN [table2] ON [table2].[Id] = [table1].[fkName]
ORDER BY [table2].[Name]
But I don't get the correct listing.
Any advice on this? Thanks in advance,
A simple and portable approach to this greatest-n-per-group problem is to filter with a subquery:
select t1.millis, t2.name, t1.price
from table1 t1
inner join table2 t2 on t2.id = t1.fkName
where t1.millis = (select max(t11.millis) from table1 t11 where t11.fkName = t1.fkName)
order by t1.millis desc
using Common Table Expression:
;with [LastPrice] as (
select [Millis], [Price], ROW_NUMBER() over (Partition by [fkName] order by [Millis] desc) rn
from [table1]
)
SELECT DISTINCT [LastPrice].[Millis],[table2].[Name],[LastPrice].[Price]
FROM [LastPrice]
JOIN [table2] ON [table2].[Id] = [LastPrice].[fkName]
WHERE [LastPrice].rn = 1
ORDER BY [table2].[Name]

sql - ignore duplicates while joining

I have two tables.
Table1 is 1591 rows. Table2 is 270 rows.
I want to fetch specific column data from Table2 based on some condition between them and also exclude duplicates which are in Table2. Which I mean to join the tables but get only one value from Table2 even if the condition has occurred more than time. The result should be exactly 1591 rows.
I tried to make Left,Right, Inner joins but the data comes more than or less 1591.
Example
Table1
type,address,name
40,blabla,Adam
20,blablabla,Joe
Table2
type,currency
40,usd
40,gbp
40,omr
Joining on 'type'
Result
type,address,name,currency
40,blabla,name,usd
20,blblbla,Joe,null
try this it has to work
select *
from
Table1 h
inner join
(select type,currency,ROW_NUMBER()over (partition by type order by
currency) as rn
from
Table2
) sr on
sr.type=h.type
and rn=1
Try this. It's standard SQL, therefore, it should work on your rdbms system.
select * from Table1 AS t
LEFT OUTER JOIN Table2 AS y ON t.[type] = y.[type] and y.currency IN (SELECT MAX(currency) FROM Table2 GROUP BY [type])
If you want to control which currency is joined, consider altering Table2 by adding a new column active/non active and modifying accordingly the JOIN clause.
You can use outer apply if it's supported.
select a.type, a.address, a.name, b.currency
from Table1 a
outer apply (
select top 1 currency
from Table2
where Table2.type = a.type
) b
I typical way to do this uses a correlated subquery. This guarantees that all rows in the first table are kept. And it generates an error if more than one row is returned from the second.
So:
select t1.*,
(select t2.currency
from table2 t2
where t2.type = t1.type
fetch first 1 row only
) as currency
from table1 t1;
You don't specify what database you are using, so this uses standard syntax for returning one row. Some databases use limit or top instead.

Can the result of a subquery be joined with itself?

Let's say I need to find the oldest animal in each zoo. It's a typical maximum-of-a-group sort of query. Only here's a complication: the zebras and giraffes are stored in separate tables. To get a listing of all animals, be they giraffes or zebras, I can do this:
(SELECT id,zoo,age FROM zebras
UNION ALL
SELECT id,zoo,age FROM giraffes) t1
Then given t1, I could build a typical maximum-of-a-group query:
SELECT t1.*
FROM t1
JOIN
(SELECT zoo,max(age) as max_age
FROM t1
GROUP BY zoo) t2
ON (t1.zoo = t2.zoo)
Clearly I could store t1 as a temporary table, but is there a way I could do this all within one query, and without having to repeat the definition of t1? (Please let's not discuss modifications to the table design; I want to focus on the issue of working with the subquery result.)
Here is a link to the with clause.
Understanding the WITH Clause
with t1 as
(select id, zoo, age from zebras
union all
select id, zoo, age from giraffes)
select t1.*
from t1
join
(SELECT zoo,max(age) as max_age
FROM t1
GROUP BY zoo) t2
on (t1.zoo = t2.zoo);
Note: You could move t2 up to your with clause as well.
Note 2: An alternative solution is to simply create t1 as a view and use it in your query instead.
To find the oldest animal, you should use wjndoq functions:
select z.*
from (select z.*,
row_number() over (partition by zoo order by age desc) as seqnum
from ( <subquery to union all animals>) z
)
where seqnum = 1