MySQL: Do not insert a new row if defined rows are same - php

I have a table which I get sampling values: AeroSamples
id time temperature pressure humidity
I sample the values at a 5 minute period. Before inserting a new row into the table, I check if the last row's temperature, pressure and humidity values are same with current values. If so, I do not want to add a new row. Else A new record could be added.
I do this like that:
SELECT temperature, pressure, humidity FROM AeroSamples ORDER BY id DESC LIMIT 1
When I get the last values, I compare three fields with current values which is the way I do not like:
if($row["temperature"] !== $curTemp || $row["pressure"] !== $curPres || $row["humidity"] !== $curHumi)
{
$db->prepare("INSERT INTO AeroSamples (temperature, pressure, humidity) VALUES(:t,:p,:h)");
...
}
How can I do this SQL only?
Does ON DUPLICATE KEY UPDATE ... help me? I do not think so. Because I am not sure if it is valid for multiple fields at a time.

The previous values will not be the same, because the time is different. Alas.
You can do this using the insert . . . select syntax. The idea is to select the last row inserted and use a where clause to filter the rows. The filter will return no rows (and hence no insert) when the values are the same:
insert into AeroSamples(temperature, pressure, humidity)
select :t, :p, :h
from (select temperature, pressure, humidity
from AeroSamples
order by id desc
limit 1
) as1
where as1.temperature <> :t or as1.pressure <> :p or as1.humidity <> :h;

In order to use ON DUPLICATE you will need to add a unique index to your table.
create unique index aerosamples_ux1 on AeroSamples(temperature, pressure, humidity);
than you can use ON DUPLICATE KEY UPDATE or ON DUPLICATE KEY IGNORE inside your queries... also keep in mind if you dont use ON DUPLICATE you query will give you an error and won't add a duplicate record after adding this index.

Related

Prevent Select sql from select the same data from DB PHP

I Have some question about the Seq in PHP.
I create 1 tabel to maintain the sequence table,
ex. table is sequence and the field is seq(start from 1)
The sequence should be unique value.
The problem is.
there is 2 process which is run parallel that will use it.
and I got the error message that say duplicate value.
The question.
How to lock the table from another select query?
this is my code
//select seq
$sqlSeq = "select seq from sequence for update";
$resultSeq = pg_query($sqlSeq);
$rowSeq = pg_fetch_assoc($resultSeq);
$seqCif = $rowSeq['seq'];
//INSERT
$sqlInsert1 ="insert into TEST (customer_id) values( '".$seqCif."')";
//UPDATE
$sqlInsert1 .= "update sequence set seq=seq+1;" ;
Can you help me for this case?
Many Thanks befor..
One simple way to make the operation atomic and to guarantee an incremental id without gaps is to turn the statement to an insert ... select ... query:
insert into test(customer_id)
select coalesce(max(customer_id), 0) + 1 from test

INSERT MULTIPLE ROWS in Gerund Table using Insert Into Select

I used INSERT INTO SELECT to copy values (multiple rows) from one table to another. Now, my problem is how do I insert rows with its corresponding IDs from different tables (since it's normalized) into a gerund table because it only outputs one row in my gerund table. What should I do to insert multiple rows and their corresponding IDs in the gerund table.
My code for the gerund table goes like this.
$insert = "INSERT INTO table1 SELECT * FROM sourcetable"; // where id1 is pk of table1.
$result =mysqli_query($conn,$insert)
$id1=mysqli_insert_id($conn);
Now table 1 has inserted multiple rows same as the other 2 tables.
Assuming id.. are the foreign keys
INSERT INTO gerundtable (pk, id1,id2,id3) VALUES ($id1,$id2,$id3);
My problem is it doesn't yield multiple rows.
According to MySql documentation:
For a multiple-row insert, LAST_INSERT_ID() and mysql_insert_id() actually return the AUTO_INCREMENT key from the first of the inserted rows. This enables multiple-row inserts to be reproduced correctly on other servers in a replication setup.
So, grab the number of records being copied, and the LAST_INSERT_ID() and you should be able to map exact IDs with each copied row.
In the lines of:
$mysqli->query("Insert Into dest_table Select * from source_table");
$n = $mysqli->affected_rows; // number of copied rows
$id1 = $mysqli->insert_id; // new ID of the first copied row
$id2 = $mysqli->insert_id + 1; // new ID of the second copied row
$id3 = $mysqli->insert_id + 2; // new ID of the third copied row
...
$mysqli->query("INSERT INTO gerundtable (pk, id1,id2,id3) VALUES ($id1,$id2,$id3)");
Thank you for trying to understand and also answering my question. I resolved my own code. I used while loop to get the ids of every row and didn't use INSERT INTO SELECT.
Here is the run down. SInce I'm just using my phone bare with my way posting.
$sqlselect = SELECT * FROM table1;
While($row=mysqli_fetch_array(table1){
$insertquery...
$id1=mysqli_insert_id($conn)
$insertgerundtable = INSERT INTO gerundtable VALUES ( $id1, $id2);
}

Insert data with MAX(id) and values of status at the same time

I was trying with this code but it didn't work. it's always get the MAX(eq_no) as 0
$sql1 =mysqli_query($con, "SELECT MAX(eq_no) AS val FROM tech_add_equip");
$sql2 = "INSERT INTO time (eq_no,status_no) VALUES ('$val', 4 );";
if (!mysqli_query($con,$sql2)) {
die('Error: ' . mysqli_error($con)); };
Finally, after I try with this code, it inserts in the right number of MAX(eq_no) but i still cant insert the values of status_no
INSERT INTO time (eq_no) SELECT MAX(eq_no) AS vale FROM tech_add_equip
Could you suggest me what did i missing in the code?
Thank you for your helping
One row returned from SELECT a,b,c statement in sub query is equivalent to set of values that is otherwise hardcoded as ('a-value','b-value','c-value')*. You can hardcode a value within select as well:
INSERT INTO time (eq_no, status_no)
SELECT MAX(eq_no), 4
FROM tech_add_equip
No need for aliases within select - order of columns matters.
*) One row result can be used for IN() clause. Another row would become set of values after comma - can't be uset for IN(), but it works ok for INSERT
('row1-a-value', 'row1-b-value'), ('row2-a-value', 'row2-b-value')
$max = SELECT MAX( customer_id ) FROM customers;
INSERT INTO customers( customer_id, statusno )
VALUES ($max , 4)

putting values in between the ascending database column

Following is my database in mysql:
Id Username Password
1 admin admin
2 jay jay1
3 suman xyza
4 chintan abcde
This is my code in php:
$fetchid = mysql_query(" SELECT MAX(Id) As max From user;");
$row = mysql_fetch_array($fetchid);
$largest = $row['max'];
$largest++;
$user= $_POST['username'];
$pass= $_POST['password'];
$result = mysql_query(" INSERT INTO `proshell`.`user` (
`Id` ,
`Username` ,
`Password`
)"."
VALUES (
'".$largest."', '".$user."', '".$pass."'
);");
Problem:
Now if I delete row with Id=1 and then re-enter the data then it should use ID=1 then Again I reinsert the data it use ID=5
It works like this:
if I delete row with Id=1 and then re-enter the data the Id it gets is 5 but then 1 is free so,
What should I write to perform that task.
First, if you set your Id column to AUTO_INCREMENT you don't need the following part in your code at all:
$fetchid = mysql_query(" SELECT MAX(Id) As max From user;");
$row = mysql_fetch_array($fetchid);
$largest = $row['max'];
$largest++;
Because AUTO_INCREMENT will automatic add new value to your ID colume.
But if you don't set it to AUTO_INCREMENT, the above code will grab the MAXIMUM ID value (in this case, 4).
When you re-enter your data again after you delete the row 1, the MAXIMUM ID still 4, so your new ID value will be 5 (from $largest++;).
.....
If you really need to use consecutive ids as you PK, you need to re-write you code but I suggest you to use UUID for you ID column instead.
You can easily generate UUID by using uuid().
How about the UUID performance? Refer to Dancrumb's answer about this:
A UUID is a Universally Unique ID. It's the universally part that you should be considering here.
Do you really need the IDs to be universally unique? If so, then UUIDs
may be your only choice.
I would strongly suggest that if you do use UUIDs, you store them as a
number and not as a string. If you have 50M+ records, then the saving
in storage space will improve your performance (although I couldn't
say by how much).
If your IDs do not need to be universally unique, then I don't think
that you can do much better then just using auto_increment, which
guarantees that IDs will be unique within a table (since the value
will increment each time)
see. UUID performance in MySQL?
EDIT: I don't suggest you run query on the whole table just to find the MAX ID value before inserting new value everytime, because it will give you a performance penalty (Imagine that if you have million rows and must query on them everytime just to insert a new row, how much workload causes to your server).
It is better to do the INSERT just as INSERT, no more than that.
EDIT2:
If you really want to use consecutive ids, then how about this solution?
Create new TABLE just for store the ids for insert (new ids and the ids that you deleted).
For example:
CREATE TABLE cons_ids (
ids INT PRIMARY KEY,
is_marker TINYINT DEFAULT 0
);
then initial ids with values from 1-100 and set marker to be '1' on some position, e.g. 80th of whole table. This 'marker' uses to fill your ids when it's nearly to empty.
When you need to INSERT new Id to your first table, use:
$result = mysql_query("SELECT ids, marker FROM cons_ids ORDER BY ids ASC LIMIT 1;");
$row = mysql_fetch_row($result);
and use $row[0] for the following code:
INSERT INTO yourtable (Id, Username, Password)
VALUES ($row[0], $username, $password);
DELETE FROM cons_ids
WHERE ids = $row[0];
This code will automatically insert the lowest number in cons_ids as your Id and remove it from the cons_ids table. (so next time you do insert, it will be the next lowest number)
Then following with this code:
if ($row[1] == 1) {
//add new 100 ids start from the highest ids number in cons_ids table
//and set new marker to 80th position again
}
Now each time you delete a row from your first table, you just add the Id from the row that you deleted to cons_ids, and when you do INSERT again, it will use the Id number that you just deleted.
For example: your current ids in cons_ids is 46-150 and you delete row with Id = 14 from first table, this 14 will add to your cons_ids and the value will become 14, and 46-150. So next time you do INSERT to your first table, your Id will be 14!!.
Hope my little trick will help you solve your problem :)
P.S. This is just an example, you can modify it to improve its performance.
First of all, as I understand, you are selecting highest column ID which should be always the last one (since you set auto-increment on ID column).
But what are you trying to do is actually filling up holes after delete query, right?
If you are really looking for such approach, try to bypass delete operation by making new boolean column where you flag record if it is active or not (true/false).
SQL table change:
Id Username Password Active
1 admin admin false
2 jay jay1 true
3 suman xyza false
4 chintan abcde true
PHP request:
$fetchid = mysql_query(" SELECT MIN(Id) As min FROM user WHERE active = false;");
$result = mysql_query(" INSERT INTO `proshell`.`user` (
`Id` ,
`Username` ,
`Password`
`Active`
)"."
VALUES (
'".$largest."', '".$user."', '".$pass."', 'true'
);");

determine if mysql values are in same row

How would this be done? I would like to search the database row by row. I might even print out the entire list of the database row by row. But I would also like to show record 1400 for example and determine the info on that row - such as name, gender and country.
Is it possible to use the rownum function to get this done? Or would I need to use a where in the query? But even so how would I determine the row number? Thanks.
Make one column as ID, make it PK and auto_increment. Then your query shell be something like this for #1400 row:
$pdo
->prepare(
"SELECT `name`, `gender`, `country`
FROM `foo_table` WHERE `id` = :id"
)
->execute([':id' => 1400]);
You can use user defined variables to get your rownumber in MySQL
set #nr = 0;
Now you can use this variable (same connection!) in your query
SELECT
#nr := (#nr + 1) rownumber,
*
FROM
table
see: http://dev.mysql.com/doc/refman/5.5/en/user-variables.html
do your select and add
LIMIT n,1
this will skip to n-th element(1400) and show just one result

Categories