I have a table
id | entry | field | value
1 | 1 | name | Egon
2 | 1 | sname | Smith
3 | 1 | city | Los Angeles
4 | 2 | name | Stephe
5 | 2 | sname | Mueller
6 | 2 | city | New York
where id is the PK and autoincrements. Lines with the same entry belong together, they are kind of a dataset. I want to add new lines for a new entry (which should have the value 3).
My Question is: how can I obtain the next value for entry in a way, that it is unique?
At the moment im using something like
SELECT MAX(entry)+1
but when two queries are made at the same time, I'll get entry = "3" for both of them. I'm coding in PHP.
Use the sequence that you already got as a unique identifier at INSERT (don't leave this task to PHP):
INSERT INTO "my_table" ("entry", "field", "value") VALUES (currval(('"my_current_id_sequence"'::text)::regclass), 'any_field_info', 'any_value_info');
This way postgres will use the right number EVERYTIME.
Another aproach is to create a sequence and use it on INSERT as well, just use nextval(('"my_new_sequence"'::text)::regclass) as the value of entry and you can even use it as a default value.
If you need to know which value was used just add RETURNING entry to your INSERT
CREATE SEQUENCE alt_serial START 101;
ALTER TABLE "my_table"
ALTER COLUMN "entry" SET DEFAULT nextval(('"alt_serial"'::text)::regclass);
INSERT INTO "my_table" ("entry", "field", "value") VALUES (DEFAULT, 'any_field_info', 'any_value_info') RETURNING entry;
you can do some kind of loop that increments the entry every loop. If you want to add more lines with the same entry, pass more arguments to it in 1 loop.
class foo{
protected $foo = [];
public function set_foo($arguments = []){
$this->foo = $arguments;
}
public function insert_rows(){
$entry = // last entry from the db (number)- your logic here
$num_of_foos = count($this->foo);
$i = 0;
$query = 'INSERT INTO table(entry, field, value ) VALUES';
while($i<$num_of_foos){
if($i>1){$query .= ',';} // adds the comma if loop repeats more than once
$query .= '("';
$query .= $entry; // entry number for the first item
$query .= ',' . $this->foo[$i] . ',' . $some_Value;
$query .= '")';
$i++;
} // end of while loop
$entry++;
} // end of function insert_rows()
} // end of class foo
//now all you need to do is set the foo
$foo = new foo;
$foo->set_foo('lalala'); // sets one argument with new entry
$foo->set_foo('jajaja'); // sets another argument with new entry
$foo->set_foo('lala', 'jaja'); // sets two arguments with the same entry
You need to:
create a sequence
CREATE SEQUENCE table_entry_seq;
Then, when you need to add a row with a new entry, get the next value of the sequence:
SELECT nextval(('"table_entry_seq"'::text)::regclass)
Related
function randomUnique(){
return $randomString =rand(0, 9999); //generate random key
}
function insert($uid,$name,$email){
$link = mysqli_connect("localhost", "root", "", "dummy");
$query = "insert into `usertbl`(`uid`,`name`,`email`)
values('".$uid."','".$name."','".$email."');";
if(mysqli_query($link, $query)){
return $rval = 1;
}else if(mysqli_errno($link) == 1062){
insert(randomUnique(),$name,$email);
}else if(mysqli_errno($link != 1062)){
return $rval = 2;// unsuccessful query
}
}
$uid = randomUnique();
$name = "sam";
$email = "sam#domain.com";
$msg_code = insert ($uid,$name,$email);
echo $msg_code;
I have 4 columns in the table :
id(PK AI),uid(varchar unique),name(varchar),email(varchar).
When I want to create a new user entry.A random key is generated using the function 'randomUnique()'.And I have the column 'id' set to AI so it tries to input the details, but if the key repeats that error number 1062 is returned back from mysql.Everything runs well except for id column which is set to AI. the column value is skipped once if one key is a duplicate.
The above code is a recursive function so the number of values skipped in column 'id' is directly proportional to the number of times the function is called.
Example:
id | uid | name | email
1 | 438 | dan | dan#domail.com
2 | 3688 | nick | nick#domain.com
4 | 410 | sid | sid#domain.com
Here, we can see number 3 has skipped bcoz either random number function gave us a number 438 or 3688 which tends to throw back an error and our recursive function repeats once skipping the number 3 and entering 4 next time on successful execution.
I need to fix the auto increment so it enters the value into proper sequence .
I cannot change the structure of the table.
You can check whether an entry already exists with that uid before performing the INSERT operation, e.g.
SELECT COUNT(*) FROM table WHERE uid = '$uid';
This will return you the count of records that have the newly generated uid. You can check this count and perform the INSERT only if count is 0. If not, you can call the function again to generate anoter random value.
In each function calling you are creating new db link, may be for this situation php provided mysqli_close($link);
Either you close connection
if(mysqli_query($link, $query)){
return $rval = 1;
}else if(mysqli_errno($link) == 1062){
mysqli_close($link);
insert(randomUnique(),$name,$email);
}else if(mysqli_errno($link != 1062)){
return $rval = 2;// unsuccessful query
}
OR simply put DB connection out of function
$link = mysqli_connect("localhost", "root", "", "dummy");
function insert($uid,$name,$email){
Use PHP's uniqid function, it generates a proper unique is.
http://php.net/manual/en/function.uniqid.php
What is this is being used for? You may be able to use the id column which will perform much faster and is already guaranteed to be unique.
I'm working on a project, in which I should generate at least 70000 codes which contain 8 alphanumeric characters. The codes must be unique. currently I am using php to generate these codes with the following function :
function random_unique_serial($length, PDO $conn) {
$codeCheck=FALSE;
while (!$codeCheck) {
$characters = '0123456789abcdefghijklmnopqrstuvwxyz';
$charactersLength = strlen($characters);
$randomCode = '';
for ($i = 0; $i < $length; $i++) {
$randomCode .= $characters[rand(0, $charactersLength - 1)];
}
$sql = "SELECT * FROM codes WHERE code=:code";
$st = $conn->prepare($sql);
$st->bindvalue(":code", $randomCode, PDO::PARAM_STR);
$st->execute();
$count = $st->rowcount();
if ($count==0) {
$codeCheck=TRUE;
} else {
$codeCheck=FALSE;
}
}
return $randomCode;
}
As you see this codes checks the database for every single code generated to make sure it is not a duplicate. This should work theoretically. However this is very slow and causes the request to time out. I tried increasing execution time but that also didn't help.
Then I decided to use a database side approach and used this solution :
Generating a random & unique 8 character string using MySQL
This is also very slow and some of the generated codes are less than 8 characters long.
could you please suggest a better solution?
Create your table structure:
CREATE TABLE t (code CHAR(8) CHARACTER SET ascii COLLATE ascii_general_ci NOT NULL UNIQUE);
Define a PHP function to generate a random string:
function random_string(integer $length = 8): string {
return bin2hex(mcrypt_create_iv(ceil($length/2), MCRYPT_DEV_URANDOM));
}
Use PHP to build a multi-value INSERT statement, ram that into the database, count how many were inserted, and repeat until the required number are inserted:
function insert_records(\PDO $pdo, integer $need = 70000): void {
$have = 0;
while ($have < $need) {
// generate multi value INSERT
$sql = 'INSERT IGNORE INTO t VALUES ';
for ($i = 1; $i < $need; $i++) {
$sql .= sprintf('("%s"),', random_string());
}
$sql .= sprintf('("%s");', random_string());
// pass to database and ask how many records were inserted
$result = $pdo->query($sql);
$count = $result->rowCount();
// adjust bookkeeping values so we know how many we have and how many
// we need
$need -= $count;
$have += $count;
}
}
On my machine (Amazon Linux c2.small), the run time for 70k records is about 2 seconds:
real 0m2.136s
user 0m1.256s
sys 0m0.212s
The relevant tricks in this code, to make it fast, are:
Sending the minimum number of SQL statements necessary to generate the needed number of records. Using a multi-value insert - INSERT INTO ... VALUES (), (), ... (); - really helps this as it minimizes the total amount of statement processing MySQL has to do and it tells us how many records were inserted without having to do another query.
Using INSERT IGNORE to avoid having to check for the existence of every single code we insert, which is really really expensive.
Using the fastest possible string generating function we can for our needs. In my experience, mcrypt_create_iv is a fast generator that is cryptographically secure, so it provides an ideal balance of security and performance.
Using the ASCII character set and fixed width CHAR to remove unnecessary byte overhead and UNIQUE to enforce de-duplication.
I'd do that with mysql alone, a stored procedure will help - you can still create and call that with php. The stored procedure uses the substring of a md5 hash, created from rand(). The column where the string is to be inserted needs to be unique. Replace table name and column in in this part:
insert ignore into foo (`uniqueString`)
delimiter //
create procedure createRandomString (in num int)
begin
declare i int default 0;
while i < num do
insert ignore into foo (`uniqueString`) values (substr(md5(rand()), 1, 8));
set i = i + 1;
end while;
end //
delimiter ;
call createRandomString (70000);
I did a quick test, I got 69934 random unique strings inserted on a remote db (from the 70000 runs) within 10s 603ms. Running the same procedure with 80000 as parameter
call createRandomString(80000);
runs 12s 434ms for me, inserting 77354 rows - so you have at least 70000 in little time.
Will produce results like this:
If you want to make sure to have exactly the number of rows inserted as called, use this (but note to set the max_sp_recursion_depth to what it was before after calling the procedure, default is 0):
delimiter //
create procedure createRandomString2 (in num int)
begin
declare i int default 0;
while i < num do
insert ignore into foo (uniqueString) values (substr(md5(rand()), 1, 8));
set i = i + 1;
end while;
if (select count(id) from foo) < num then
call createRandomString2(num - (select count(id) from foo));
END IF;
end //
delimiter ;
set max_sp_recursion_depth = 100;
call createRandomString7 (70000);
set max_sp_recursion_depth = 0;
Here's one idea...
Here I'm inserting (approx.) 16, unique, 3-character (0-9/a-z) strings...
DROP TABLE IF EXISTS my_table;
CREATE TABLE my_table (my_string CHAR(3) NOT NULL PRIMARY KEY);
INSERT INTO my_table
SELECT CONCAT(SUBSTR('0123456789abcdefghihjlmnopqrstuvwxyz',(RAND()*35)+1,1)
,SUBSTR('0123456789abcdefghihjlmnopqrstuvwxyz',(RAND()*35)+1,1)
,SUBSTR('0123456789abcdefghihjlmnopqrstuvwxyz',(RAND()*35)+1,1)
) x;
//Repeat this block as necessary
INSERT IGNORE INTO my_table
SELECT CONCAT(SUBSTR('0123456789abcdefghihjlmnopqrstuvwxyz',(RAND()*35)+1,1)
,SUBSTR('0123456789abcdefghihjlmnopqrstuvwxyz',(RAND()*35)+1,1)
,SUBSTR('0123456789abcdefghihjlmnopqrstuvwxyz',(RAND()*35)+1,1)
) x
FROM my_table;
//End of block
SELECT * FROM my_table;
+-----------+
| my_string |
+-----------+
| 0he |
| 112 |
| 24c |
| 322 |
| 4b7 |
| 7vq |
| as7 |
| g7n |
| h66 |
| i54 |
| idd |
| m62 |
| mqt |
| obh |
| x75 |
| xz4 |
+-----------+
Eight digit numbers are guaranteed unique: 00000000, 00000001, 00000002, ... If you don't want the codes so obvious, then select eight different sets of ten alphanumeric characters to replace the ten digits in a given position. There will still be a pattern, but it will be less obvious: ql4id78sk, ql4id78s3, ql4id78sa, ...
Beyond that, you could encrypt the original numbers, and the encryptions are guaranteed unique. A 32 bit block cypher will produce four byte results, giving eight hex characters.
I want to be able to add an array of strings to a table so that each string is a new row (in PHP).
This is it in psuedo-code:
$Array = "10000,10001,10002,10003";
$Data = "ImportantData";
mysqli_query($db, "INSERT INTO MyTable(`id`,`data`) VALUES($Array, $Data)");
So that a previously empty table would look like:
id | data
------------------------
10000 | ImportantData
10001 | ImportantData
10002 | ImportantData
10003 | ImportantData
In an update script, with those rows already established, I could just say:
mysqli_query($db, "UPDATE MyTable SET data = $Data WHERE `id` IN($Array));
However I want it to create rows, not just update old ones.
Is there any way I can do this?
Just create a foreach loop on $Array, and insert the data. I assume you want to update it if it exists as it makes little sense to create a new record with the same PK, so use the following (assumes you are using PHP PDO
INSERT INTO MyTable (id,data) VALUES (:id,:data) ON DUPLICATE KEY UPDATE data=:data;
Use REPLACE INTO:
REPLACE INTO table SET id = 10001, data = 'new important data';
MySQL documentation: http://dev.mysql.com/doc/refman/5.0/en/replace.html
I'd like to insert a multidimensional array into a MySQL Database field so that it can then easily be read from the database at a later date back into an array. What's the best way to achieve this?
I've tried the following to no avail:
$id = "MXB-487"
$items = Array(Array("Coffee", "Blend", "500"), Array("Coffee1", "Blend1", "250"));
$items = implode(",", $items);
mysqli_query($con,"INSERT INTO carts (id, items)
VALUES ($id, $items)");
/*Code that pulls the array from the Database based on id and stores in variable $info*/
restored_mdarray = explode(",", $info);
ID in MySql, is usually unique (I'm pretty sure you specified it that way). So, you can't share the ID for multiple items. Also, imploding will end up with the following query:
INSERT INTO carts (id, items) VALUES(MXB-487, Array, Array)
Because you have a multidimensional array you're trying to implode, it doesn't recursively implode.
What you should do is loop through the objects, and I'm not sure how the relationship here works, but it looks like you need a relation table to connect those items. Consider the following structure:
Carts:
+----------+-----------+
| ID | Name |
+----------+-----------+
--<-| MXB-487 | Blah blah |
| +----------+-----------+
|
| Items:
| +----------+-----------+----------+-----------+
| | Cart_ID | Type1 | Type 2 | Amount |
| +----------+-----------+----------+-----------+
--->| MXB-487 | Coffee | Blend | 500 |
+----------+-----------+----------+-----------+
And in order to implement that in PHP, you'd do something like this:
<?php
$id = "MXB-487";
$items = array(
array("Coffee", "Blend", "500"),
array("Coffee1", "Blend1", "500"),
);
$sql = "INSERT INTO actions (cart_id, type1, type2, amount) VALUES ";
$items_sql = array();
if (count($items)) {
foreach ($items as $item) {
$items_sql[] = "('$id', '{$item[0]}', '{$item[1]}', '{$item[2]}')";
}
}
$sql .= implode(", ", $items_sql);
And then run the query.
It will look like this:
INSERT INTO actions (cart_id, type1, type2, amount) VALUES ('MXB-487', 'Coffee', 'Blend', '500'), ('MXB-487', 'Coffee1', 'Blend1', '500')
Which you can later select as such:
<?php
$id = "MXB-487";
$sql = "SELECT * FROM actions WHERE (cart_id = '$id')";
Though as a side note, I suggest you look at PDO and how to bind values, or at least learn to escape your values in the SQL to prevent future injections.
I speculated the structure of the tables, of course you can modify to your needs.
To connect the tables properly via SQL (to fasten the fetching later on) you can use FOREIGN KEY when you define the table:
CREATE TABLE actions (
id INT(11) NOT NULL AUTO_INCREMENT,
cart_id VARCHAR(32) NOT NULL,
type1 VARCHAR(32) NOT NULL,
type2 VARCHAR(32) NOT NULL,
amount INT NOT NULL,
PRIMARY KEY (id),
FOREIGN KEY (cart_id) REFERENCES carts(id)
)
Use serialize:
$a = array(array(1,2,3), array(3,4,5));
$b = serialize($a);
# write $b to and later read $b from database
$c = unserialize($b);
$a == $c # => true
How can I uniquely identify two or more columns, that I have used table named address in the database, now address is has fields like street name, suite name and street num.
strnum | strnam | sutname
1 | xyz | 32
1 | xyz | 32
now how can I uniquely these three columns. That is I want to check whether these three column are already inserted or not. If any field valus is changed than its ok, it will insert new one. but in case all three similar field..Help me to combinely identify these three fields.
You do it by adding unique constraint.
ALTER TABLE your_table ADD UNIQUE(strnum, strnam, sutname);
Then you do the following:
INSERT IGNORE INTO your_table (strnum, strnam, sutname) VALUES ('1', 'xyz', 'etc');
If the value exists already - no insert will happen and no errors will be raised (that's what the IGNORE part is).
By the way why do you use such short and vague column names? It's not the DOS era any more, you can be descriptive with your column names.
$query = "SELECT * FROM `address` WHERE `strnum` = '$strnum' AND `strnam` = '$strnam' AND `sutname` = '$sutname' LIMIT 1";
$result = mysql_query($query);
if (!mysql_num_rows($result)) {
// If you get to here, there is no existing record
$query = "INSERT INTO `address` (`strnum`,`strnam`,`sutname`) VALUES ('$strnum','$strnam','$sutname')";
if (!mysql_query($query)) print('Insert failed!');
} else print('Record already exists!');
EDIT I just added a missing ; so this parses...
just add them as unique keys in table structure and you'll not be able to insert two of them
you can do something like this
SELECT * FROM table WHERE col1 = $something AND col2 = $something2 AND col3 = $something3
(remember about escpaing php variables)
if the record is returned it means it exists. You can also add LIMIT 1 to make it faster.
if your question is about ENSURING that no duplicates occur in the table (for those 3 columns), then probably the best solution is to add UNIQUE index on those three columns.