Keep same table structure but only MAX values - mysql

Hi all,
How can I, in the most efficient way, keep only the records with the max weights values per color but same table structure (all columns) without using subselects ?
I was trying: max(over partition by colour) but I don't know how to condition further. (not sure if this is the best way)
Thanks!

If you mean to delete those rows:
In CTE Block the record with 1 value shows MAX weight. So When Joining main table with CTE adding extra condition RN = 1, cause that other value that RN is not equal 1 become NULL; and there are the record should be deleted and max value remain in table.
With CTE As (
Select BRICK_ID, Row_Number() Over (Partition By color, order by Weight DESC) RN
From table_name
)
DELETE tbl
FROM CTE
RIGHT JOIN table_name tbl ON CTE.BRICK_ID = tbl.BRICK_ID AND RN = 1
WHERE CTE.BRICK_ID IS NULL
And if you want to move the records with max weight to another table with same structure, use this one:
With CTE As (
Select BRICK_ID, Row_Number() Over (Partition By color, order by Weight DESC) RN
From table_name
)
Select tbl.*
into new_table_name
FROM CTE
INNER JOIN table_name tbl ON CTE.BRICK_ID = tbl.BRICK_ID

You can delete rows and keep the max Weight for each colour group by using an updatable CTE, such as:
with delme as (
select *, row_number() over(partition by colour order by weight desc) rn
from Yourtable
)
delete from delme where rn > 1;

Related

How to count occurrences with derived tables in SQL?

I have this very simple table:
CREATE TABLE MyTable
(
Id INT(6) PRIMARY KEY,
Name VARCHAR(200) /* NOT UNIQUE */
);
If I want the Name(s) that is(are) the most frequent and the corresponding count(s), I can neither do this
SELECT Name, total
FROM table2
WHERE total = (SELECT MAX(total) FROM (SELECT Name, COUNT(*) AS total
FROM MyTable GROUP BY Name) table2);
nor this
SELECT Name, total
FROM (SELECT Name, COUNT(*) AS total FROM MyTable GROUP BY Name) table1
WHERE total = (SELECT MAX(total) FROM table1);
Also, (let's say the maximum count is 4) in the second proposition, if I replace the third line by
WHERE total = 4;
it works.
Why is that so?
Thanks a lot
You can try the following:
WITH stats as
(
SELECT Name
,COUNT(id) as count_ids
FROM MyTable
GROUP BY Name
)
SELECT Name
,count_ids
FROM
(
SELECT Name
,count_ids
,RANK() OVER(ORDER BY count_ids DESC) as rank_ -- this ranks all names
FROM stats
) s
WHERE rank_ = 1 -- the most popular ```
This should work in TSQL.
Your queries can't be executed because "total" is no column in your table. It's not sufficient to have it within a sub query, you also have to make sure the sub query will be executed, produces the desired result and then you can use this.
You should also consider to use a window function like proposed in Dimi's answer.
The advantage of such a function is that it can be much easier to read.
But you need to be careful since such functions often differ depending on the DB type.
If you want to go your way with a sub query, you can do something like this:
SELECT name, COUNT(name) AS total FROM myTable
GROUP BY name
HAVING COUNT(name) =
(SELECT MAX(sub.total) AS highestCount FROM
(SELECT Name, COUNT(*) AS total
FROM MyTable GROUP BY Name) sub);
I created a fiddle example which shows both queries mentioned here will produce the same and correct result:
db<>fiddle

return max value for each group but when there is a tie, return one with lower id in MySQL

I am using MySQL 8.0
My table looks like this:
group user_id score
A 1 33
B 2 22
A 3 22
B 4 22
I want it to return
group user_id score
A 1 33
B 2 22
note that even though group B has same score user_id=2 is final winner since he/she has lower user_id
How to improve from below query...?
SELECT group, user_id, max(score)
from table
Thanks in advance!
#Ambleu you are on the right track using MAX(), but to do this you need to use it in addition to MIN(), and also use a sub query to get the MAX(score) like this:
SELECT `mt`.`group`,
MIN(`mt`.`user_id`) AS `user_id`,
`mt`.`score`
FROM `myTable` AS `mt`
JOIN (SELECT `group`,
MAX(`score`) AS `score`
FROM `myTable`
GROUP BY `group`) AS `der` ON `der`.`group` = `mt`.`group`
AND `der`.`score` = `mt`.`score`
GROUP BY `mt`.`group`, `mt`.`score`
Here are your tables and the solution query mocked up on db-fiddle.
If this doesn't get you what you need please let me know and I'll try to assist further.
In MySQL 8.0, I would recommend window functions:
select grp, user_id, score
fom (
select t.*,
row_number() over(partition by grp order by score desc, user_id) rn
from mytable t
) t
where rn = 1
Alternatively, you can use a correlated subquery for filtering:
select t.*
from mytable t
where user_id = (
select t1.user_id
from mytable t1
where t1.grp = t.grp
order by t1.score desc, t1.user_id limit 1
)
The second query would take advantage of an index on (grp, score desc, user_id).
Side note: group is a language keyword, hence a poor choice for a column name. I renamed it to grp in the queries.

Query to fetch second highest salary from table [duplicate]

What is the simplest SQL query to find the second largest integer value in a specific column?
There are maybe duplicate values in the column.
SELECT MAX( col )
FROM table
WHERE col < ( SELECT MAX( col )
FROM table )
SELECT MAX(col)
FROM table
WHERE col NOT IN ( SELECT MAX(col)
FROM table
);
In T-Sql there are two ways:
--filter out the max
select max( col )
from [table]
where col < (
select max( col )
from [table] )
--sort top two then bottom one
select top 1 col
from (
select top 2 col
from [table]
order by col) topTwo
order by col desc
In Microsoft SQL the first way is twice as fast as the second, even if the column in question is clustered.
This is because the sort operation is relatively slow compared to the table or index scan that the max aggregation uses.
Alternatively, in Microsoft SQL 2005 and above you can use the ROW_NUMBER() function:
select col
from (
select ROW_NUMBER() over (order by col asc) as 'rowNum', col
from [table] ) withRowNum
where rowNum = 2
I see both some SQL Server specific and some MySQL specific solutions here, so you might want to clarify which database you need. Though if I had to guess I'd say SQL Server since this is trivial in MySQL.
I also see some solutions that won't work because they fail to take into account the possibility for duplicates, so be careful which ones you accept. Finally, I see a few that will work but that will make two complete scans of the table. You want to make sure the 2nd scan is only looking at 2 values.
SQL Server (pre-2012):
SELECT MIN([column]) AS [column]
FROM (
SELECT TOP 2 [column]
FROM [Table]
GROUP BY [column]
ORDER BY [column] DESC
) a
MySQL:
SELECT `column`
FROM `table`
GROUP BY `column`
ORDER BY `column` DESC
LIMIT 1,1
Update:
SQL Server 2012 now supports a much cleaner (and standard) OFFSET/FETCH syntax:
SELECT [column]
FROM [Table]
GROUP BY [column]
ORDER BY [column] DESC
OFFSET 1 ROWS
FETCH NEXT 1 ROWS ONLY;
I suppose you can do something like:
SELECT *
FROM Table
ORDER BY NumericalColumn DESC
LIMIT 1 OFFSET 1
or
SELECT *
FROM Table ORDER BY NumericalColumn DESC
LIMIT (1, 1)
depending on your database server. Hint: SQL Server doesn't do LIMIT.
The easiest would be to get the second value from this result set in the application:
SELECT DISTINCT value
FROM Table
ORDER BY value DESC
LIMIT 2
But if you must select the second value using SQL, how about:
SELECT MIN(value)
FROM ( SELECT DISTINCT value
FROM Table
ORDER BY value DESC
LIMIT 2
) AS t
you can find the second largest value of column by using the following query
SELECT *
FROM TableName a
WHERE
2 = (SELECT count(DISTINCT(b.ColumnName))
FROM TableName b WHERE
a.ColumnName <= b.ColumnName);
you can find more details on the following link
http://www.abhishekbpatel.com/2012/12/how-to-get-nth-maximum-and-minimun.html
MSSQL
SELECT *
FROM [Users]
order by UserId desc OFFSET 1 ROW
FETCH NEXT 1 ROW ONLY;
MySQL
SELECT *
FROM Users
order by UserId desc LIMIT 1 OFFSET 1
No need of sub queries ... just skip one row and select second rows after order by descending
A very simple query to find the second largest value
SELECT `Column`
FROM `Table`
ORDER BY `Column` DESC
LIMIT 1,1;
SELECT MAX(Salary)
FROM Employee
WHERE Salary NOT IN ( SELECT MAX(Salary)
FROM Employee
)
This query will return the maximum salary, from the result - which not contains maximum salary from overall table.
Old question I know, but this gave me a better exec plan:
SELECT TOP 1 LEAD(MAX (column)) OVER (ORDER BY column desc)
FROM TABLE
GROUP BY column
This is very simple code, you can try this :-
ex :
Table name = test
salary
1000
1500
1450
7500
MSSQL Code to get 2nd largest value
select salary from test order by salary desc offset 1 rows fetch next 1 rows only;
here 'offset 1 rows' means 2nd row of table and 'fetch next 1 rows only' is for show only that 1 row. if you dont use 'fetch next 1 rows only' then it shows all the rows from the second row.
Simplest of all
select sal
from salary
order by sal desc
limit 1 offset 1
select * from (select ROW_NUMBER() over (Order by Col_x desc) as Row, Col_1
from table_1)as table_new tn inner join table_1 t1
on tn.col_1 = t1.col_1
where row = 2
Hope this help to get the value for any row.....
Use this query.
SELECT MAX( colname )
FROM Tablename
where colname < (
SELECT MAX( colname )
FROM Tablename)
select min(sal) from emp where sal in
(select TOP 2 (sal) from emp order by sal desc)
Note
sal is col name
emp is table name
select col_name
from (
select dense_rank() over (order by col_name desc) as 'rank', col_name
from table_name ) withrank
where rank = 2
SELECT
*
FROM
table
WHERE
column < (SELECT max(columnq) FROM table)
ORDER BY
column DESC LIMIT 1
It is the most esiest way:
SELECT
Column name
FROM
Table name
ORDER BY
Column name DESC
LIMIT 1,1
As you mentioned duplicate values . In such case you may use DISTINCT and GROUP BY to find out second highest value
Here is a table
salary
:
GROUP BY
SELECT amount FROM salary
GROUP by amount
ORDER BY amount DESC
LIMIT 1 , 1
DISTINCT
SELECT DISTINCT amount
FROM salary
ORDER BY amount DESC
LIMIT 1 , 1
First portion of LIMIT = starting index
Second portion of LIMIT = how many value
Tom, believe this will fail when there is more than one value returned in select max([COLUMN_NAME]) from [TABLE_NAME] section. i.e. where there are more than 2 values in the data set.
Slight modification to your query will work -
select max([COLUMN_NAME])
from [TABLE_NAME]
where [COLUMN_NAME] IN ( select max([COLUMN_NAME])
from [TABLE_NAME]
)
select max(COL_NAME)
from TABLE_NAME
where COL_NAME in ( select COL_NAME
from TABLE_NAME
where COL_NAME < ( select max(COL_NAME)
from TABLE_NAME
)
);
subquery returns all values other than the largest.
select the max value from the returned list.
This is an another way to find the second largest value of a column.Consider the table 'Student' and column 'Age'.Then the query is,
select top 1 Age
from Student
where Age in ( select distinct top 2 Age
from Student order by Age desc
) order by Age asc
select age
from student
group by id having age< ( select max(age)
from student
)
order by age
limit 1
SELECT MAX(sal)
FROM emp
WHERE sal NOT IN ( SELECT top 3 sal
FROM emp order by sal desc
)
this will return the third highest sal of emp table
select max(column_name)
from table_name
where column_name not in ( select max(column_name)
from table_name
);
not in is a condition that exclude the highest value of column_name.
Reference : programmer interview
Something like this? I haven't tested it, though:
select top 1 x
from (
select top 2 distinct x
from y
order by x desc
) z
order by x
See How to select the nth row in a SQL database table?.
Sybase SQL Anywhere supports:
SELECT TOP 1 START AT 2 value from table ORDER BY value
Using a correlated query:
Select * from x x1 where 1 = (select count(*) from x where x1.a < a)
select * from emp e where 3>=(select count(distinct salary)
from emp where s.salary<=salary)
This query selects the maximum three salaries. If two emp get the same salary this does not affect the query.

MySQL: check that a set of queries returns the same row count : : but I don't know what the count is

We read values from a set of sensors, occasionally a reading or two is lost for a particular sensor , so now and again I run a query to see if all sensors have the same record count.
GROUP BY sensor_id HAVING COUNT(*) != xxx;
So I run a query once to visually get a value of xxx and then run it again to see if any vary.
But is there any clever way of doing this automatically in a single query?
You could do:
HAVING COUNT(*) != (SELECT MAX(count) FROM (
SELECT COUNT(*) AS count FROM my_table GROUP BY sensor_id
) t)
Or else group again by the count in each group (and ignore the first result):
SELECT count, GROUP_CONCAT(sensor_id) AS sensors
FROM (
SELECT sensor_id, COUNT(*) AS count FROM my_table GROUP BY sensor_id
) t
GROUP BY count
ORDER BY count DESC
LIMIT 1, 18446744073709551615
SELECT sensor_id,COUNT(*) AS count
FROM table
GROUP BY sensor_id
ORDER BY count
Will show a list of the sensor_id along with a count of all the records it has, you can then manually check to see if any vary.
SELECT * FROM (
SELECT sensor_id,COUNT(*) AS count
FROM table
GROUP BY sensor_id
) AS t1
GROUP BY count
Will show all the counts that vary, but the group by will lose information about which sensor_ids have which counts.
---EDIT---
Taken a bit from both mine and eggyal's answer and created this, for the count that is most frequent I call the id default, and then for any values that stand out I have given them separate rows. This way you maintain the readability of a table if you have many results Multi Row, but also have a simple one row column if all counts are the same One Row. If however you are happy with the concocted strings then go with eggyal's answer.
Might be a bit over the top but here goes:
select 'default' as id,t5.c1 as count from(
select id,count(*) as c1 from your_table group by id having count(*)=
(select t4.count from
(
select max(t3.count2) as max,t3.count as count from
(
select count(*) as count2,t2.count from
(
SELECT id,COUNT(*) AS count
FROM your_table
GROUP BY id
) as t2
GROUP BY count
) as t3
) as t4)) as t5 group by count
union all
select t5.id as id,t5.c1 as count from(
select id,count(*) as c1 from your_table group by id having count(*)<>
(select t4.count from
(
select max(t3.count2) as max,t3.count as count from
(
select count(*) as count2,t2.count from
(
SELECT id,COUNT(*) AS count
FROM your_table
GROUP BY id
) as t2
GROUP BY count
) as t3
) as t4)) as t5

MySql Sql MAX and SUM error

select sum(value) as 'Value',max(value)
from table_name where sum(value)=max(sum(value)) group by id_name;
The error is: Invalid use of group function (ErrorNr. 1111)
Any idea?
Thanks.
Can you maybe try
SELECT Value, MXValue
FROM (
select sum(value) as 'Value',max(value) MXValue
from table_name
group by id_name
) as t1
order by value desc
LIMIT 0,1
From MySQL Forums :: General :: selecting MAX(SUM())
Or you could try something like
SELECT id_name,
Value
FROM (
select id_name,sum(value) as 'Value'
from table_name
group by id_name
) t
WHERE Value = (
SELECT TOP 1 SUM(Value) Mx
FROM table_name
GROUP BY id_name
ORDER BY SUM(Value) DESC
)
Or even with an Inner join
SELECT id_name,
Value
FROM (
select id_name,sum(value) as Value
from table_name
group by id_name
) t INNER JOIN
(
SELECT TOP 1 SUM(Value) Mx
FROM table_name
GROUP BY id_name
ORDER BY SUM(Value) DESC
) m ON Value = Mx
The =max(sum(value)) part requires comparing the results of two grouped selects, not just one. (The max of the sum.)
Let's step back, though: What information are you actually trying to get? Because the sum of the values in the table is unique; there is no minimum or maximum (or, depending on your viewpoint, there is -- the value is its own minimum and maximum). You'd need to apply some further criteria in there for the results to be meaningful, and in doing so you'd probably need to be doing a join or a subselect with some criteria.