Non repeating and minimum value - mysql

I have a requirement where in i need to find the lowest and non repeating value in a sql column. Let me describe it
Sno. User amount
1. 1001 $0.02
2. 1002 $0.03
3. 1003 $0.04
5. 1004 $0.02
6. 1005 $0.05
In this scenario, in the amount column although $0.02 is the minimum, but we can see that it is also preset twice(repeating) in the column, so the next minimum and non repeating value is $0.03 and which is what I want.
I tried using Distinct but it gives all the values in the amount column I just need the one. I don't care about the higher values $0.04 and $0.05 here.

You can use MIN() with GROUP BY.. HAVING:
SELECT MIN(amount)
FROM (SELECT amount
FROM table
GROUP BY amount
HAVING COUNT(1) = 1) a

You can do this easily with a GROUP BY and HAVING while taking the MIN:
Select Min(Amount)
From
(
Select Amount
From YourTable
Group By Amount
Having Count(*) = 1
) As A

I would do this with GROUP BY and LIMIT:
SELECT amount
FROM t
GROUP BY amount
HAVING COUNT(*) = 1
ORDER BY amount ASC
LIMIT 1;
Or, if you really wanted to be fancy with no aggregation:
select t.*
from t
where not exists (select 1 from t t2 where t2.sno = t.sno and t2.amount = t.amount)
order by t.amount
limit 1;
The advantage of this approach is that you can get all the other values from the column as well.

Related

Mysql calculate with the max() value

I'm a bit stuck cause am not sure if I am looking the wrong way casue I can't find anything related to what I am looking for. So I want to give an example for what I am trying to do. NOTE: not real scenario.
I have a count on a field:
SELECT count(user_id)
FROM usersgroups
group by user_id
Now I want to make a calc with the max value from the count. Something like:
SELECT count(user_id) as count,
SUM(max(count(user_id)) / count(user_id)) as blub
FROM usergroups
group by user_id
But I get error invalid use of group function cause I think I cant use the COUNT() function inside the SUM function?
So is there any other way to make that calculation.
P.S. the calc is for calculating the percentage of the max value to the record/current value.
UPDATE
So what I expect is a percentage like
count | percentage
5 | 1
4 | 0.8
3 | 0.6
2 | 0.3
1 | 0.2
5/5 = 1
4/5 = 0.8
3/5 = 0.6
2/5 = 0.4
1/5 = 0.2
In a separate Derived Table, you can fetch the maximum count value out of all the counts. I have simply used ORDER BY COUNT(user_id) DESC LIMIT 1 to fetch the same.
CROSS JOIN this result-set with the usergroups table, so that every row in the usergroups table has access to the maximum count value.
Now, you can simply use the GROUP BY and appropriate aggregation to determine the "percent".
Note that, for GROUP BY to be valid, SELECT clause must contain either aggregated columns/expressions only, or the columns specified in the GROUP BY clause. That is why MAX() is used over the maximum count value. Since that value is only a scalar, so MAX() will return the same value only.
Try the following:
SELECT
ug.user_id,
COUNT(ug.user_id) AS user_count,
COUNT(ug.user_id) / MAX(mcnt.count) AS percent
FROM
usergroups AS ug
CROSS JOIN
(
SELECT COUNT(user_id) AS count
FROM usersgroups
GROUP BY user_id
ORDER BY COUNT(user_id) DESC LIMIT 1
) AS mcnt
GROUP BY ug.user_id
ORDER BY user_count DESC
Count available user_id as subquery, then divide user_id values by the sum of count.
select user_id/ sum(count) as percentage
from(
select count(user_id) as count , user_id
from usergroups
where user_id != 0
group by user_id
) as A
group by count, user_id

Access two rows based on one columns but also access other columns for those rows

I have a table with columns weight,height,knee,date,id I wanted to find two rows in the same table- the first row is min(weight) and the other is max(weight). How do I also access the dates and ids for these two rows even though everything is in the same table.
Try searching for the min and max weight:
SELECT *
FROM yourTable
WHERE
weight = (SELECT MIN(weight) FROM yourTable) OR
weight = (SELECT MAX(weight) FROM yourTable);
Note that if there be more than one record tied for the min/max weight, then the above query could yield more than 2 records. If ties are a possibility, then you should provide logic for how to handle this.
If you are using MySQL 8 or later, and have access to ROW_NUMBER, then there is a slick solution here:
SELECT *
FROM
(
SELECT *,
ROW_NUMBER() OVER (ORDER BY weight) rn1,
ROW_NUMBER() OVER (ORDER BY weight DESC) rn2
FROM yourTable
) t
WHERE 1 IN (rn1, rn2);
union all comes to mind:
(select t.*
from t
order by weight asc
limit 1
) union all
(select t.*
from t
order by weight desc
limit 1
);
This should be pretty optimal in terms of performance if you have an index on weight.
This guarantees exactly two rows in the result set, even if there are ties.

How to select data where a field has a min value in MySQL?

I want to select data from a table in MySQL where a specific field has the minimum value, I've tried this:
SELECT * FROM pieces WHERE MIN(price)
Please any help?
this will give you result that has the minimum price on all records.
SELECT *
FROM pieces
WHERE price = ( SELECT MIN(price) FROM pieces )
SQLFiddle Demo
This is how I would do it, assuming I understand the question.
SELECT * FROM pieces ORDER BY price ASC LIMIT 1
If you are trying to select multiple rows where each of them may have the same minimum price, then #JohnWoo's answer should suffice.
Basically here we are just ordering the results by the price in ascending order (ASC) and taking the first row of the result.
This also works:
SELECT
pieces.*
FROM
pieces inner join (select min(price) as minprice from pieces) mn
on pieces.price = mn.minprice
(since this version doesn't have a where condition with a subquery, it could be used if you need to UPDATE the table, but if you just need to SELECT i would reccommend to use John Woo solution)
Use HAVING MIN(...)
Something like:
SELECT MIN(price) AS price, pricegroup
FROM articles_prices
WHERE articleID=10
GROUP BY pricegroup
HAVING MIN(price) > 0;
Efficient way (with any number of records):
SELECT id, name, MIN(price) FROM (select * from table order by price) as t group by id
In fact, depends what you want to get:
- Just the min value:
SELECT MIN(price) FROM pieces
A table (multiples rows) whith the min value: Is as John Woo said above.
But, if can be different rows with same min value, the best is ORDER them from another column, because after or later you will need to do it (starting from John Woo answere):
SELECT * FROM pieces
WHERE price = ( SELECT MIN(price) FROM pieces)
ORDER BY stock ASC
To improve #sberry's answer, if the column has a null value then simply doing ORDER BY would select a row with null value. Add a WHERE clause to get correct results:
SELECT * FROM pieces
WHERE price>0
ORDER BY price ASC
LIMIT 1;
Or if there is a chance of having negative values and/or VARCHAR, etc. do:
SELECT * FROM pieces
WHERE price IS NOT NULL
ORDER BY price ASC
LIMIT 1;
To make it simpler
SELECT *,MIN(price) FROM prod LIMIT 1
Put * so it will display the all record of the minimum value

SQL query to average values only if more than one value, not equal to 0, exits?

I only want to calculate an AVG of values if two or more non-zero values exist for a specific item_id. If two or more non-zero values do not exist, I do not want to calculate the AVG.
The current SQL is below. Perhaps there should be an if clause first?... any ideas?
SELECT AVG( days_since ) AS days_out
FROM (
SELECT days_since
FROM user_123
WHERE item_id = 645
AND days_since <> 0
ORDER BY id DESC
LIMIT 5
) AS recent
Seems like an If clause might work;
IF SELECT COUNT (*), item_id, days_since >= 2
where days_since <>0, then perform AVG...
What about:
SELECT AVG(days_since) AS days_out
FROM User_123
WHERE Item_ID = 645
AND Days_Since <> 0
HAVING COUNT(*) > 1
I'm not sure what the ORDER BY and LIMIT clauses are for, so you'll have to adapt the answer to reimpose the conditions implied by them.
How to keep it working while reapplying Order By and Limit. These are used so that only the 5 most recent entries are used in the Average calculation.
SELECT AVG(days_since) AS days_out
FROM (SELECT days_since
FROM User_123
WHERE Item_ID = 645
AND Days_Since <> 0
ORDER BY ID DESC
LIMIT 5
) AS u
HAVING COUNT(*) > 1;

SELECT rows with minimum count(*)

Let's say i have a simple table voting with columns
id(primaryKey),token(int),candidate(int),rank(int).
I want to extract all rows having specific rank,grouped by candidate and most importantly only with minimum count(*).
So far i have reached
SELECT candidate, count( * ) AS count
FROM voting
WHERE rank =1
AND candidate <200
GROUP BY candidate
HAVING count = min( count )
But,it is returning empty set.If i replace min(count) with actual minimum value it works properly.
I have also tried
SELECT candidate,min(count)
FROM (SELECT candidate,count(*) AS count
FROM voting
where rank = 1
AND candidate < 200
group by candidate
order by count(*)
) AS temp
But this resulted in only 1 row,I have 3 rows with same min count but with different candidates.I want all these 3 rows.
Can anyone help me.The no.of rows with same minimum count(*) value will also help.
Sample is quite a big,so i am showing some dummy values
1 $sampleToken1 101 1
2 $sampleToken2 102 1
3 $sampleToken3 103 1
4 $sampleToken4 102 1
Here ,when grouped according to candidate there are 3 rows combining with count( * ) results
candidate count( * )
101 1
103 1
102 2
I want the top 2 rows to be showed i.e with count(*) = 1 or whatever is the minimum
Try to use this script as pattern -
-- find minimum count
SELECT MIN(cnt) INTO #min FROM (SELECT COUNT(*) cnt FROM voting GROUP BY candidate) t;
-- show records with minimum count
SELECT * FROM voting t1
JOIN (SELECT id FROM voting GROUP BY candidate HAVING COUNT(*) = #min) t2
ON t1.candidate = t2.candidate;
Remove your HAVING keyword completely, it is not correctly written.
and add SUB SELECT into the where clause to fit that criteria.
(ie. select cand, count(*) as count from voting where rank = 1 and count = (select ..... )
The HAVING keyword can not use the MIN function in the way you are trying. Replace the MIN function with an absolute value such as HAVING count > 10