MySQL update values of unique column - mysql

I am trying to:
select values from a unique column that match some condition, for example, numbers that can be divided by 2
alter those numbers
write the result back in the table. If altered numbers duplicate with numbers that are already there, skip this row insertion
Create the table:
CREATE TABLE test (
id INT AUTO_INCREMENT PRIMARY KEY,
number INT NOT NULL UNIQUE
)
Populate:
INSERT test(number)
VALUES
(4), (5), (6), (9)
Do the trick:
UPDATE test
SET number = number - 1
WHERE MOD(number, 2) > 0
(this code fails with Duplicate entry '4' for key 'test.number')
I would like to end up with the following table:
id number
1 4
3 6
4 8
I want number 5 with id 2 to be changed to 4 (number = number-1), and then to be rejected because it duplicates number 4 with id 1
I have tried the following also:
INSERT INTO test
(id, number)
SELECT id, (number-1) AS number
FROM test
WHERE MOD(number, 2) > 0
ON DUPLICATE KEY UPDATE id = id
But this fails with "Column 'id' in field list is ambiguous"
Why do I want to do this? I have a table with a unique time series column, that is quite large. Values in that column are supposed to have one minute interval between them, for example:
19-Oct-2018 05:59:00
19-Oct-2018 06:00:00
19-Oct-2018 06:01:00
but some of them have non-zero seconds:
19-Oct-2018 05:59:00
19-Oct-2018 06:00:00
19-Oct-2018 06:00:20
19-Oct-2018 06:01:20
19-Oct-2018 06:02:20
19-Oct-2018 06:03:00
So I want to alter those by rounding up to the neighboring minute, but that leads to duplicates sometimes, and those duplicates should be discarded.
I have found some similar topics here, but was unable to figure out how to implement the answers to my case.

So, the answer, that was found in comments:
UPDATE IGNORE test
SET number = number-1
WHERE MOD(number, 2) > 0
request2:
DELETE FROM test
WHERE MOD(number, 2) > 0

Related

Mysql insert if not available, update if partial available and exit if fully available

i need to take the appropriate action depending on whether the values are found, partially found or not available at all.
This is my table:
id. emp_code. ot_date. ot_hours
1 123 2021-05-01 3
2 567 2021-05-01 1
Now i have these 3 data:
Data #1
emp_code: 123
ot_date: 2021-05-01
ot_hours: 3
Data #2
emp_code: 123
ot_date: 2021-05-02
ot_hours: 3
Data #3
emp_code: 567
ot_date: 2021-05-01
ot_hours: 2.5
This is my logic to decide and take action:
select emp_code, ot_date where values are (emp_code, ot_date)
from ot_forecast
if it exist
select emp_code, ot_dat,ot_hours where values are (emp_code, ot_date, ot_hours)
from ot_forecast
if exist then exit
else update values (emp_code, ot_date, ot_hours)
else insert values (emp_code, ot_date, ot_hours)
Based on my logic, data 1 will be skipped, data 2 will be inserted and data 3 will be updated
Problem is, I can't figure out how to put this in codes. I'm already stuck at the first line.
Hope someone can guide me with this.
Thanks
If you create emp_code,ot_date as a unique (or primary (id seems pointless)) key, that enables INSERT ON DUPLICATE KEY UPDATE.
CREATE UNIQUE INDEX ot_forecast ( emp_code, ot_date)
Your query will become:
INSERT INTO ot_forecast
SET emp_code = xxx, ot_date= yyyy, ot_hours = zzzz
ON DUPLICATE KEY UPDATE ot_hours = zzzz
The first case of yours as the select will incur an update and maybe this is ok as its effectively a no-op.
If you where using MariaDB you could also use INSERT RETURNING:
INSERT INTO ot_forecast
SET emp_code = xxx, ot_date= yyyy, ot_hours = zzzz
ON DUPLICATE KEY UPDATE ot_hours = zzzz
RETURNING emp_code, ot_date, ot_hours

Insert data into a column only if it has NULL value, else update it [duplicate]

This question already has answers here:
MySQL on duplicate key update
(2 answers)
Closed 1 year ago.
I want to update data into a column in a table only if the data sent from the HTML page is not NULL or ''. Else, that column must not be touched. Example :-
table_1
id name age rent
==========================================
1 Name 1 25 1000
2 Name 2 28 NULL
3 Name 3 35 1500
4 Name 4 44 3200
5 name 5 42 NULL
LET THE DATA SENT FROM HTML PAGE IS STOERED IN A VARIABLE today_rent AND THIS VARIABLE IS SENT TO MYSQL.
MySQL Query
IF(today_rent !=null OR today_rent != '') THEN
UPDATE table_1 SET rent=today_rent WHERE id=2
END IF;
Is there any other way to do it?
Add an index
CREATE UNIQUE INDEX idx ON test (id, (CASE WHEN rent IS NULL THEN 0 ELSE id END));
Then use
INSERT INTO test (id, rent)
VALUES (#id,#new_rent)
ON DUPLICATE KEY UPDATE rent = VALUES(rent);
https://dbfiddle.uk/?rdbms=mysql_8.0&fiddle=c48a44a6268e2e1710162b337efa592b
PS. The query does not set name and age columns - but their setting necessity is not described in the question.

Finding count of unique value before a character

I have a some entries in database table rows as follows.
101 - 1
101 - 2
101 - 3
102 - 1
102 - 2
102 - 3
103
I need to get the result of SELECT Query for count as '3' since there are 101 and 102 are the only number before the -.
So is there any way to find the unique value in db table columns before a character?
EDIT : I have entries even without the - .
In case your entries have always the format you have provided us, you just have to find the position of the '-' character, split the values, get the first n characters and count the distinct values
This works for SQL Server, otherwise informs us about what DBMS you are using or replace the functions with the ones of your DBMS on your own
SELECT COUNT(DISTINCT SUBSTRING(val,0,CHARINDEX('-', val))) from YourTable
create table T1
(
id int primary key identity,
col1 varchar(20)
)
insert into T1 values('101 - 1'),('101 - 2'),('101 - 3'),('102 - 1'),('102 - 2'),('102 - 3')
select SUBSTRING(col1,0,CHARINDEX(' ',col1)) as 'Value',count(*) as 'Count' from T1 group by SUBSTRING(col1,0,CHARINDEX(' ',col1))

MySQL: Select from list of values

I was wondering if I could select given values from a list and populate rows? For example, SELECT 1 as one, 2 as two, 3 as three will populate columns:
one | two | three
------------------------
1 | 2 | 3
I'm looking for a script that populates rows, something like:
values
-------
1
2
3
4
Thanks!
you can union each one if you want like so
SELECT 1 AS numbers
UNION SELECT 2
UNION SELECT 3
a much simpler way to do something like this would be to make a table with an auto incremented id... insert into another column in the table an empty string... then just select the auto incremented id
CREATE TEMPORARY TABLE tmp (
id INTEGER NOT NULL AUTO_INCREMENT PRIMARY KEY,
val varchar(1)
);
INSERT INTO tmp (val)
values
(""),
(""),
(""),
(""),
(""),
(""),
(""),
(""),
(""),
("");
select id from tmp;
DEMO
To get a few numbers, the approach from John Ruddell is the probably the most convenient, I can easily incorporate an inline view in any query I'm needing to run.
When I need a lot of numbers, for example, 1 through 4000, I can do something like this:
CREATE TABLE digit (d INT(11) NOT NULL PRIMARY KEY);
INSERT INTO digit (d) VALUES (0),(1),(2),(3),(4),(5),(6),(7),(8),(9);
SELECT thousands.d*1000+hundreds.d*100+tens.d*10+ones.d+1 AS n
FROM digit ones
CROSS
JOIN digit tens
CROSS
JOIN digit hundreds
CROSS
JOIN digit thousands
WHERE thousands.d < 4
I can also add a HAVING clause if the boundaries of the numbers I need aren't quite as neat, e.g
HAVING n >= 121
AND n <= 2499
If I want to ensure the "numbers" are returned in order, I'll add an ORDER BY clause:
ORDER BY n

how find "holes" in auto_increment column?

when I DELETE, as example, the id 3, I have this:
id | name
1 |
2 |
4 |
5 |
...
now, I want to search for the missing id(s), because i want to fill the id again with:
INSERT INTO xx (id,...) VALUES (3,...)
is there a way to search for "holes" in the auto_increment index?
thanks!
You can find the top value of gaps like this:
select t1.id - 1 as missing_id
from mytable t1
left join mytable t2 on t2.id = t1.id - 1
where t2.id is null
The purpose of AUTO_INCREMENT is to generate simple unique and meaningless identifiers for your rows. As soon as you plan to re-use those IDs, they're no longer unique (not at least in time) so I have the impression that you are not using the right tool for the job. If you decide to get rid of AUTO_INCREMENT, you can do all your inserts with the same algorithm.
As about the SQL code, this query will match existing rows with the rows that has the next ID:
SELECT a.foo_id, b.foo_id
FROM foo a
LEFT JOIN foo b ON a.foo_id=b.foo_id-1
E.g.:
1 NULL
4 NULL
10 NULL
12 NULL
17 NULL
19 20
20 NULL
24 25
25 26
26 27
27 NULL
So it's easy to filter out rows and get the first gap:
SELECT MIN(a.foo_id)+1 AS next_id
FROM foo a
LEFT JOIN foo b ON a.foo_id=b.foo_id-1
WHERE b.foo_id IS NULL
Take this as a starting point because it still needs some tweaking:
You need to consider the case where the lowest available number is the lowest possible one.
You need to lock the table to handle concurrent inserts.
In my computer it's slow as hell with big tables.
I think the only way you can do this is with a loop:
Any other solutions wont show gaps bigger than 1:
insert into XX values (1)
insert into XX values (2)
insert into XX values (4)
insert into XX values (5)
insert into XX values (10)
declare #min int
declare #max int
select #min=MIN(ID) from xx
select #max=MAX(ID) from xx
while #min<#max begin
if not exists(select 1 from XX where id = #min+1) BEGIN
print 'GAP: '+ cast(#min +1 as varchar(10))
END
set #min=#min+1
end
result:
GAP: 3
GAP: 6
GAP: 7
GAP: 8
GAP: 9
First, I agree with the comments that you shouldn't try filling in holes. You won't be able to find all the holes with a single SQL statement. You'll have to loop through all possible numbers starting with 1 until you find a hole. You could write a sql function to do this for you that could then be used in a function. So if you wrote a function called find_first_hole you could then call it in an insert like:
INSERT INTO xx (id, ...) VALUES (find_first_hole(), ...)
This is a gaps&island problem, see my (and other) replies here and here. In most cases, gaps&islands problems are most elegantly solved using recursive CTE's, which are not available in mysql.