sql: keep only the minimum value if two rows have duplicate id - mysql

Below is my sample data. Row 3 and 4 have the same st_case (the primary key), but their dist_min are different. I want to keep the row with the minimum dist_min value. And please notice that there could be more than 2 duplicate rows associate with the same st_case. Thank you so much for the help!

In MySQL, you can do this with a delete and join:
delete s
from sample s left join
(select st_case, min(dist_min) as mindm
from sample s
group by st_case
) ss
on ss.st_case = s.st_case and s.dist_min > ss.mindm;

You can try this one:
DELETE t1 FROM table AS t1
LEFT JOIN table t2 ON t1.st_case = t2.st_case
WHERE t1.dist_min > t2.dist_min

As SAM M suggested, I am not sure how you can have duplicate rows with same primary key.
However in case st_case is not your only key and the table has a composite key
OR had it been a non-key column,
You could write a trigger to control the insertion
Something like:
CREATE table CALC_STATUS(id varchar(40), correlatoinToken integer, requirement double)
CREATE TRIGGER keep_min BEFORE INSERT ON CALC_STATUS
FOR EACH row
BEGIN
IF NEW.correlatoinToken = correlatoinToken AND NEW.requirement <= requirement then
SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT = "A row with similar correlation token with lower requirement already exists";
ELSEIF NEW.correlatoinToken = correlatoinToken AND NEW.requirement > requirement
NEW.requirement = requirement;
END IF;
END;
And if you meant to query:
SELECT c1.* FROM CALC_STATUS c1,(SELECT st_case,MIN(dist_min) FROM CALC_STATUS GROUP BY road_id) AS c2 WHERE c1.st_case=c2.st_case

DELETE FROM sample
WHERE dist_min !=(SELECT dist_min FROM (SELECT * FROM sample) sample2
WHERE sample2.st_case = sample.st_case
ORDER BY dist_min
LIMIT 1)

I didn't get to test this so please forgive any syntax errors. SQL ranking functions can solve your problem. Essentially you group by one column and then rank by another. Then you can select only those of rank one.
SELECT *
FROM(
SELECT *, Rank() OVER (PARTITION BY 'st_case' Order by Dist_min DESC) as Rank
From 'tbl_Name')
WHERE Rank = '1'

Related

MySQL: Conditional Trigger

Is it possible to create a trigger that conditionally updates a column with a random value from another tables column.
Previously I received help to create a trigger that updates a column with a random value from another tables column: MySQL: Trigger Update with random value from another tables column. I’m trying now to make it conditionally based on another columns value.
If the users.selection column = ‘fruits’ then random select from fruits.
If the users.selection column = ‘animals’ then random from animals.
If neither ‘fruits’ nor ‘animals’ don’t update.
Here is a db-fiddle: https://dbfiddle.uk/?rdbms=mysql_8.0&fiddle=6bc76ed2c104dad0e27dd35b1da112a7
Major thanks to #Akina for getting me this far! Lots to learn.
Update (May 29th):
I still can’t figure it out. I thought maybe I would need a SELECT with IF statement first to return the selection column value but that didn’t seem to work. Basically I have tried a lot of different combinations using these examples below as templates. None of them seem to bring my closer.
Anyone have any ideas?
Examples:
SELECT T1.ID, IFNULL(T1.name, T2.name) AS name
FROM firsttable T1
LEFT JOIN secondtable T2
ON T1.T2_id = T2.id
SET final_price= CASE
WHEN currency=1 THEN 0.81*final_price
ELSE final_price
END
SET col = (
SELECT other_col
FROM other_table
WHERE other_table.table_id = table.id
);
SELECT book_name,isbn_no,
IF((SELECT COUNT(*) FROM book_mast WHERE pub_lang='English')>
(SELECT COUNT(*) FROM book_mast WHERE pub_lang<>'English'),
(CONCAT("Pages: ",no_page)),(CONCAT("Price: ",book_price)))
AS "Page / Price"
FROM book_mast;
I think you need to conditionally define what does what, if selection is fruit, then do something. else if selection is animals, then do another thing.
e.g:
CREATE TRIGGER trigger_test
BEFORE UPDATE
ON users
FOR EACH ROW
BEGIN
IF (NEW.selection = 'fruits') THEN
SET NEW.random = ( SELECT fruits
FROM list
ORDER BY RAND() LIMIT 1 );
ELSEIF (NEW.selection = 'animals') THEN
SET NEW.random = ( SELECT animals
FROM list
ORDER BY RAND() LIMIT 1 );
END IF;
END;

SQL: How to update column with unique values

Below is a MySQL query:
SELECT
COUNT(*) AS counted, employer_group
FROM
employer_survey
GROUP BY employer_group
HAVING counted > 1;
Before I alter table definition for employer_group to unique, I need to create an UPDATE statement to CONCAT() the value of created_dt to employer_group so the alter table will not fail because of values.
How do I do this? I am unable to return id column because I am using GROUP BY and HAVING.
I should mention that I want the id column returned so I may use the above SELECT with an IN clause in my UPDATE statement. This may not be the best approach.
You can do this with join:
update employer_survey es join
(select es2.employer_group
from employer_survey es2
group by es2.employer_group
having count(*) > 1
) eg
on es.employer_group = eg.employer_group
set es.employer_group = concat_ws(' ', es.employer_group, es.created_dt);

MySQL - update the row with the highest start date

I am trying to update the member row with the highest start date using:
UPDATE at_section_details a
SET a.sd_end_date = ?
, a.sd_details = ?
WHERE a.cd_id = ?
AND a.sd_start_date = (SELECT MAX(b.sd_start_date)
FROM at_section_details b
WHERE b.cd_id = ?)
The error message is:
"SQLException in updateYMGroup: java.sql.SQLException: You can't specify target table 'a' for update in FROM clause
The table structure is:
sd_id - primary key
cd_id - foreign key (many occurrences)
sd_section
sd_pack
sd_start_date
sd_end_date
sd_details
A member (cd_id) can start and then transfer out.
The member can then transfer in again (new start date). When they transfer out we want to pick up the max start date to transfer out against.
Any assistance would be greatly appreciated.
Regards,
Glyn
You should be able to use the LIMIT statement with an ORDER BY. Something along these lines:
UPDATE at_section_details a
SET a.sd_end_date=?, a.sd_details=?
WHERE a.cd_id=?
ORDER BY a.sd_start_date DESC
LIMIT 1
As it says on this post MySQL Error 1093 - Can't specify target table for update in FROM clause
In My SQL you can't have an update with the same table you are updating inside a subquery.
I would try to change your sub query to some like this
(Select x.* from (select max...) as x)
Sorry for abbreviating the code, I'm on mobile.
This query should work:
UPDATE at_section_details
JOIN (
SELECT cd_id, MAX(sd_start_date) sd_start_date
FROM at_section_details
WHERE cd_id = ?
GROUP BY cd_id
) AS t2 USING (cd_id, sd_start_date)
SET sd_end_date=?, sd_details=?;
See this SQL Fiddle for an example
You can try this mate:
UPDATE at_section_details SET sd_end_date = <input>, sd_details = <input>
WHERE cd_id IN (
SELECT cd_id FROM at_section_details
WHERE cd_id = <input>
ORDER BY sd_start_date DESC
LIMIT 1
);

Insert values in new column in Mysql

I have a table T with some data having 3 rows. Now I added a new column c.
Now I want to insert values into c for existing rows.
I do it like this :
insert into T (c) values(1),(2),(3);
But instead of updating existing data, it inserted new rows.
How can I update existing data ?
I don't want to specify where clause. I just want to add values serial wise as insert does.
You would use the UPDATE statement to assign values to columns of existing rows.
UPDATE t
SET t.c = 1
WHERE t.a = 1 ;
To assign unique, sequential integer to each existing row, you'd need to make use of the primary key, or a unique identifier from each row. In this example, we assume that the id column is unique:
UPDATE t
JOIN ( SELECT r.id
, #i := #i + 1 AS i
FROM t r
JOIN (SELECT #i := 0) n
ORDER BY r.id
) s
ON s.id = t.id
SET t.c = s.i
Actually, you can also do this:
UPDATE t
JOIN ( SELECT #i := 0 ) n
SET t.c = #i := #i + 1
ORDER BY t.id
It sounds like you might want to investigate the AUTO_INCREMENT attribute.
You can use below query
UPDATE Table
SET Col1='1', Col2='2'
and so on...
Also, you can use where condition, if you want to update data with some specified conditions, as below:
---it's just an example of query used in my database---
UPDATE City_Employee
SET City='Banglore' where (City='Delhi')
Best of luck !

Updating sort keys after delete

I have a table which has a field sort_id. In this field there are numbers from 1 to n, that define the order of the data sets.
Now I want to delete some elements and afterwards I want to reorder the table. Therefore I need a query that "finds" the gaps and changes the sort_id field according to the modifications.
Sure, I could do something like this:
SELECT sort_id FROM table WHERE id = 5
Then save the sort_id and afterwards:
DELETE FROM table WHERE id = 5
UPDATE table SET sort_id = sort_id - 1 WHERE sort_id > {id from above}
But I'd like to do the reordering process in one step.
Mladen and Arvo have good ideas, but unfortunately in MySQL you can't SELECT and UPDATE the same table in the same statement (even in a subquery). This is a known limitation of MySQL.
Here's a solution that uses MySQL user variables:
SET #i := 0;
UPDATE mytable
SET sort_id = (#i := #i + 1)
ORDER BY sort_id;
For what it's worth, I wouldn't bother doing this anyway. If your sort_id is used only for sorting and not as a kind of "row number," then the rows are still in sorted order after you delete the row where id=6. The values don't necessarily have to be consecutive for sorting.
for sql server 2005:
this is how you get the new sequence:
SELECT row_number() over(order by sort_id) as RN
FROM table
updating the table means you should join that select to your update:
update t1
set sort_id = t2.RN
FROM table t1
join (SELECT row_number() over(order by sort_id) as RN FROM table) t2
on t1.UniqueId = t2.UniqueId
I don't know MySQL syntax variations and cannot test query live, but something like next should give you at least an idea:
update table t1
set sort_id = (select count * from table t2 where t2.sort_id <= t1.sort_id)