SQL Complex Query - mysql

I'm trying to generate a query that will do the following:
I have an offer catalog table that has [Id, term, loanamount, interestrate], for every id there are multiple offers, i.e. every customer gets multiple offers. I'm trying to retrieve a dataset with the offer for each id that has [Id, max(term), max(loanamount)] and then the interest rate for the offer with the max(term) and max(loanamount) the way the I view it is the following:
SELECT a.Id as oppId,
a.MAX(Term) as maxTerm,
a.MAX(LoanAmount) as maxAmount,
b.InterestRate
FROM table a
JOIN ( SELECT InterestRate
FROM table
WHERE Id = oppId
AND Term = maxTerm
AND LoanAmount = maxAmount) b
GROUP BY Id
This doesn't seem to work so if anyone has a way to acomplish this it would be fantastic!

You can use row_number()
select * from
(
select *,row_number() over(partition by id order by Term desc, LoanAmount desc) as rn
from tablename
)A where rn=1

If I understand correctly, you can use row_number():
select t.*
from (select t.*,
row_number() over (partition by id order by term desc, loan_amount desc) as seqnum
from t
) t
where seqnum = 1

Related

Invalid use of group function for mysql

I am getting this error but I don't understand why my query doesn't work. Can someone please give me a hand?
The question is this:
SELECT activity
FROM Friends
GROUP BY activity
HAVING COUNT(activity) > MIN(COUNT(activity))
AND COUNT(activity) < MAX(COUNT(activity))
My idea is that as long as the count of the activity is larger than the activity that has the minimum count and less than the activity that has the maximum count, it should be returned. But I am having "Invalid use of group function" error which I don't understand. One possible thing that I could think of is that the parts that I am comparing with the COUNT(activity) have to be a number that is selected from the table instead of a part that has "MIN" or "MAX". But I don't understand why as they both look like the same number to me.
If your version of MySql is less than 8.0, the following will work:
select activity, count(*) as cnt from Friends group by activity
having cnt not in (
select max(cnt) as cnt from (
select activity, count(*) as cnt from Friends group by activity
) sq1
union
select min(cnt) as cnt from (
select activity, count(*) as cnt from Friends group by activity
) sq2
);
activity
cnt
Singing
2
View on DB Fiddle
Since the above SQL references the same select 3 times, namely select activity, count(*) as cnt from Friends group by activity, you might consider creating a quasi-temporary table (but there is the overhead in creating such a table to consider -- for the number of rows you actually presented, this would run more slowly):
create table t as select activity, count(*) as cnt from Friends group by activity;
select activity from t where cnt not in (
select max(cnt) as cnt from t
union
select min(cnt) as cnt from t
);
drop table t;
activity
Singing
View on DB Fiddle
If you just want data from friends table then you can use the analytical function (My sql 8.0 or higher) as follows:
select activity from
(SELECT activity, dense_rank() over (order by count(*)) as rn_asc,
dense_rank() over (order by count(*) desc) as rn_desc
FROM Friends
GROUP BY activity)
where rn_asc <> 1 and rn_dsc <> 1

Mysql Order By count?

Actually I'm working with the following table fsa_areas:
Note that each area has a responsible
Now, what I need to do, is to order the same table as following:
Note that now the results are ordered by the the responsible with more areas and at the end the responsible with less areas.
Is there a way to order them in that way?
You can use a COUNT subquery in the ORDER BY clause:
select a.*
from fsa_areas a
order by (select count(*) from fsa_areas a1 where a1.Responsible = a.Responsible) desc
Another way is to get the count in a derived table and join the base table to it
select a.*
from (
select Responsible, count(*) as cnt
from fsa_areas
group by Responsible
) r
join fsa_areas a using(Responsible)
order by r.cnt desc
In MySQL 8 you can use COUNT() as window function:
select *, count(*) over (partition by Responsible) as cnt
from fsa_areas
order by cnt desc

How to use a dynamic limit in sql query

I have a query SELECT * FROM grades WHERE userid = 4123;
I want to limit this query
I have a query SELECT * FROM grades WHERE userid = 4123 LIMIT(2);
This works great but if I want this limit to be dynamic from another query.
SELECT COUNT(id) FROM count_table WHERE course = 131;
doing this gives me a syntax error
SELECT * FROM grades WHERE userid = 4123 LIMIT (SELECT COUNT(id) FROM count_table WHERE course = 131);
if this is not possible at all, then is there an alternative way to achieve this?
please help.!
You can do it in MySQL 8.x using the ROW_NUMBER() function.
Assuming you order the rows by some column (I guessed the column ID... change it as needed), you can do:
select
g.*
from (
select
*,
row_number() over(order by id) as rn -- change ordering as needed
from grades
) g
join (
SELECT COUNT(id) as cnt FROM count_table WHERE course = 131
) c on g.rn <= c.cnt

Mysql query showing extra fields

I am trying this query:
SELECT * FROM heath_check where cid = '1' and eid in('3','5','7','1','6')
My table structure:
I want distinct eid but all other data as it is. For example I have two entries with an eid of 1 my query fetched both, but I want one which is in the second column.
SELECT *
FROM heath_check AS hc
INNER JOIN (
SELECT MAX(id) AS lastId
FROM heath_check
WHERE cid = '1' and eid in('3','5','7','1','6')
GROUP BY eid) AS lastIDs
ON hc.id = lastIDs.lastId
;
You need a subquery, like the above, to find the records you want for each value. If you had wanted the first ones, you could use MIN(id) instead; if you cannot count on sequential ids, it becomes much more complex with use of potentially non-unique timestamps (if they are even available).
Create a RowNumber grouped by eid and filter the RowNumber = 1 to get the expected result.
SELECT id, eid, cid,weight, s_blood_pressure
FROM (
SELECT *, ROW_NUMBER() OVER (PARTITION BY eid ORDER BY id DESC) AS RowNumber
FROM heath_check
WHERE cid = '1' AND eid IN ('3','5','7','1','6')
) A
WHERE RowNumber = 1

select last record from a relation

I have this situation. I have a table Orders that is related to OrderStatus.
OrderStatus
id | orderId | created
I need to retrieve the Orders with its last status. I tried this query, what I don't know if it is performant. I need to know if there are better solutions.
select Orders.id, OrderStatus.status from Orders
inner join OrderStatus on OrderStatus.id =
(select top 1 id from OrderStatus where orderId = Order.id order by created desc)
Correlated subquery is usually bad news (sometimes SQL Server can optimize it away, sometimes it acts like a really slow loop). Also not sure why you think you need DISTINCT when you're only taking the latest status, unless you don't have any primary keys...
;WITH x AS
(
SELECT o.id, os.status,
rn = ROW_NUMBER() OVER (PARTITION BY os.orderId ORDER BY created DESC)
FROM dbo.Orders AS o
INNER JOIN dbo.OrderStatus AS os
ON o.id = os.orderId
)
SELECT id, status
FROM x
WHERE rn = 1;
You can use the Row_Number function:
WITH CTE AS
(
SELECT Orders.id, OrderStatus.status,
RN = ROW_NUMBER() OVER (
PARTITION BY OrderStatus.OrderId
ORDER BY created DESC)
FROM Orders
INNER JOIN OrderStatus ON OrderStatus.OrderId = Orders.id
)
SELECT id, status
FROM CTE WHERE RN = 1
I've used a common-table-expression since it enables to filter directly and it's also very readable.