Quoting MySQL INSERT manual - same goes for UPDATE:
Use the keyword DEFAULT to set a column explicitly to its default value. This makes it easier to write INSERT statements that assign values to all but a few columns, because it enables you to avoid writing an incomplete VALUES list that does not include a value for each column in the table. Otherwise, you would have to write out the list of column names corresponding to each value in the VALUES list.
So in short if I write
INSERT INTO table1 (column1,column2) values ('value1',DEFAULT);
A new row with column2 set as its default value - whatever it may be - is inserted.
However if I prepare and execute a statement in PHP:
$statement = $pdoObject->
prepare("INSERT INTO table1 (column1,column2) values (?,?)");
$statement->execute(array('value1','DEFAULT'));
The new row will contain 'DEFAULT' as its text value - if the column is able to store text values.
Now I have written an abstraction layer to PDO (I needed it) and to get around this issue am considering to introduce a
const DEFAULT_VALUE = "randomstring";
So I could execute statements like this:
$statement->execute(array('value1',mysql::DEFAULT_VALUE));
And then in method that does the binding I'd go through values that are sent to be bound and if some are equal to self::DEFAULT_VALUE, act accordingly.
I'm pretty sure there's a better way to do this. Has someone else encountered similar situations?
The only "workaround" I know for this is to use Coalesce() and Default(fieldname)
E.g.
$pdo = new PDO("mysql:host=localhost;dbname=test", 'localonly', 'localonly');
$pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
$pdo->exec("
CREATE TEMPORARY TABLE foo (
id int auto_increment,
x int NOT NULL DEFAULT 99,
y DATETIME NOT NULL DEFAULT '2010-03-17 01:00:00',
z varchar(64) NOT NULL DEFAULT 'abc',
primary key(id)
)
");
$stmt = $pdo->prepare('
INSERT INTO
foo
(x,y,z)
VALUES
(
Coalesce(:x, Default(x)),
Coalesce(:y, Default(y)),
Coalesce(:z, Default(z))
)
');
$stmt->bindParam(':x', $x);
$stmt->bindParam(':y', $y);
$stmt->bindParam(':z', $z);
$testdata = array(
array(null, null, null),
array(1, null, 'lalala'),
array(null, '2009-12-24 18:00:00', null)
);
foreach($testdata as $row) {
list($x,$y,$z) = $row;
$stmt->execute();
}
unset($stmt);
foreach( $pdo->query('SELECT id,x,y,z FROM foo', PDO::FETCH_NUM) as $row) {
echo join(', ', $row), "\n";
}
prints
1, 99, 2010-03-17 01:00:00, abc
2, 1, 2010-03-17 01:00:00, lalala
3, 99, 2009-12-24 18:00:00, abc
I tried replying to VolkerK answer, but couldnt find how. :( I'm kinda new to all this.
Anyway, I created a mysql function to use in conjuction with his COALESCE idea
CREATE FUNCTION NULLDEFAULT(colname VARCHAR(64), tablename VARCHAR(64), dbname VARCHAR(64)) RETURNS longtext DETERMINISTIC READS SQL DATA
BEGIN
DECLARE retval longtext;
SELECT
COLUMN_DEFAULT INTO retval
FROM
information_schema.COLUMNS
WHERE
TABLE_NAME = tablename
AND
COLUMN_NAME = colname
AND
TABLE_SCHEMA = dbname;
RETURN retval;
END
You would use it like this:
$stmt = $pdo->prepare("
INSERT INTO
foo
(x,y,z)
VALUES
(
Coalesce(:x, NULLDEFAULT('x', 'foo', 'database')),
Coalesce(:y, NULLDEFAULT('y', 'foo', 'database')),
Coalesce(:z, NULLDEFAULT('z', 'foo', 'database'))
)
");
That will return null if the column has no default value, and won't trigger the "Column has no default value" Error.
Of course you could modify it to not require the database parameter
Try changing this:
$statement = $pdoObject->
prepare("INSERT INTO table1 (column1,column2) values (?,?)");
$statement->execute(array('value1','DEFAULT'));
To this:
$statement = $pdoObject->
prepare("INSERT INTO table1 (column1,column2) values (?,DEFAULT)");
$statement->execute(array('value1'));
It seems to me that your original code will give you this:
INSERT INTO table1 (column1,column2) values ('value1','DEFAULT')
My code should give you this:
INSERT INTO table1 (column1,column2) values ('value1',DEFAULT)
i think that it is writing the String 'DEFAULT ' because it is escaped by pdo so there are parametres for bindvalue where you can specify the type of the value given so you can send a null with no quotes and it will be PDO::PARAM_NULL; and then default values will be put , but i'm not sure if there are similar parameters when binding with execute
if(is_int($param)){$pdoParam = PDO::PARAM_INT;}
elseif(is_bool($param)){$pdoParam = PDO::PARAM_BOOL;}
elseif(is_null($param)){ $pdoParam = PDO::PARAM_NULL;}
elseif(is_string($param)){$pdoParam = PDO::PARAM_STR;}
else{$pdoParam = FALSE;}
$this->_query->bindValue($k,$param,$pdoParam);
Related
I'm having the following query, it contains a Temporary Table. If I use a Temporary Table, it returns an EMPTY ARRAY. If I removed the Temporary Table it returns an appropriate records.
The following SQL Query contains a simple query, I just created a Temporary Table and inserted some records and I'm doing SELECT Query in that Temporary Table. I executed the same code in phpMyAdmin, it returns an appropriate records, but in PDO returns an EMPTY ARRAY.
Sample and Simple SQL Query:
Case #1: With Temporary Table - Returns an EMPTY ARRAY
<?php
$query = <<<SQL
CREATE TEMPORARY TABLE TempContact (
ContactId int,
FirstName varchar(30),
LastName varchar(30),
IsActiveContact Boolean
);
INSERT INTO TempContact (ContactId, FirstName, LastName, IsActiveContact)
SELECT CT.ContactId, CT.FirstName, CT.LastName,
CASE WHEN SL.SalesId IS NOT NULL THEN TRUE ELSE FALSE END AS IsActiveContact
FROM Contact CT
LEFT JOIN Sales SL ON CT.ContactId = SL.ContactId;
SELECT TC.* FROM TempContact TC;
SQL;
$stmt = $db->prepare($query);
$result = $stmt->execute() ? $stmt->fetchAll() : null;
?>
Case #2: Without Temporary Table - Returns an appropriate records
<?php
$query = <<<SQL
SELECT CT.ContactId, CT.FirstName, CT.LastName,
CASE WHEN SL.SalesId IS NOT NULL THEN TRUE ELSE FALSE END AS IsActiveContact
FROM Contact CT
LEFT JOIN Sales SL ON CT.ContactId = SL.ContactId;
SQL;
$stmt = $db->prepare($query);
$result = $stmt->execute() ? $stmt->fetchAll() : null;
?>
My actual code is so complex, due to easy understanding I added this simple query.
I also checked for any error in my Query (Case #1 Query) using print_r($stmt->errorInfo());, but it returns an EMPTY ARRAY (i.e., No Error in my Query);. Moreover its not throwing any PDOException.
Kindly assist me, how to get the records from the Temporary Table SELECT
With PDO you're supposed to execute one query at a time. It's not like the SQL console where you can push in a bunch of statements at once.
You're expected to check that each query completed successfully before moving on to the next one. If you split this up into several prepare/execute pairs it will work as-is. The reason the second succeeds is because it consists of a single statement.
PHP PDO fetchAll() returns empty array while SELECTing Temporary Table
Obviously, it is not true. Anyone can run the following code utilizing a temporary table and see the result
$pdo->query("CREATE temporary TABLE tmptest (id int auto_increment primary key, name varchar(255))");
$stmt = $pdo->prepare("INSERT INTO tmptest VALUES (NULL, ?)");
foreach (['Sam','Bob','Joe'] as $name)
{
$stmt->execute([$name]);
}
$stmt = $pdo->prepare("SELECT * FROM tmptest");
$stmt->execute();
var_export($stmt->fetchAll(PDO::FETCH_KEY_PAIR));
which outputs the expected
array (
1 => 'Sam',
2 => 'Bob',
3 => 'Joe',
)
While your problem is coming from the fact that you are running multiple queries in a single call and so the first fetchAll() is naturally returns an empty result as the first query returns nothing. To get your data you should be either run your queries in separate statements or move the internal pointer to the next result and then call for fetchAll():
$pdo->query("CREATE temporary TABLE tmptest (id int auto_increment primary key, name varchar(255))");
$pdo->query("CREATE temporary TABLE tmptest2 (id int auto_increment primary key, name varchar(255))");
$stmt = $pdo->prepare("INSERT INTO tmptest VALUES (NULL, ?)");
foreach (['Sam','Bob','Joe'] as $name)
{
$stmt->execute([$name]);
}
$stmt = $pdo->prepare("INSERT INTO tmptest2 SELECT * from tmptest;SELECT * FROM tmptest2");
$stmt->execute();
$stmt->nextRowset();
var_export($stmt->fetchAll(PDO::FETCH_KEY_PAIR));
I wonder if there is a way to pass some values into the parameters option on the sqlsrv_query function. I tried a few things but could not get it to work.
This query is what I want to be executed:
SELECT id, name, etc
FROM sqlTable
WHERE id IN ('1', '2', '100', '314')
I want to pass the WHERE IN values using the params option, like this:
$q = "SELECT id FROM sqlTable WHERE id IN ?";
$p = array(array('1', '2', '100', '314'));
sqlsrv_query($connection, $q, $p);
Right now I'm passing the values directly into the query string, but for obvious security reasons I want to pass them as parameters into the function.
Anyone any idea on how to achieve this?
Consider PDO binded parameters which you can pass a defined array in execute(). However, you would need to prepare the statement, knowing number of IN() clause items in advance.
try {
$dbh = new PDO("sqlsrv:server=$server;database=$database",$username,$password);
$sql = "SELECT * FROM sqlTable WHERE id IN (:first, :second, :third, :fourth)";
$STH = $dbh->prepare($sql);
$nums = array('1', '2', '100', '314');
$STH->execute($nums);
}
catch(PDOException $e) {
echo $e->getMessage()."\n";
}
So I have figured out this issue on the sql side. Now I pass a comma separated string with the ids to the query using the params in the sqlsrv_query() function. The query sets the string in a temporarily variable. Using a splitting function every id is stored in a temporarily table. As last I JOIN the temporarily table with the table from witch I want to get the results.
Splitting function in SQL:
CREATE FUNCTION dbo.splitstring ( #stringToSplit VARCHAR(MAX) )
RETURNS
#returnList TABLE ([Name] [nvarchar] (500))
AS
BEGIN
DECLARE #name NVARCHAR(255)
DECLARE #pos INT
WHILE CHARINDEX(',', #stringToSplit) > 0
BEGIN
SELECT #pos = CHARINDEX(',', #stringToSplit)
SELECT #name = SUBSTRING(#stringToSplit, 1, #pos-1)
INSERT INTO #returnList
SELECT #name
SELECT #stringToSplit = SUBSTRING(#stringToSplit, #pos+1, LEN(#stringToSplit)-#pos)
END
INSERT INTO #returnList
SELECT #stringToSplit
RETURN
END
PHP code and SQL query:
$q = "
DECLARE #inStr varchar(max)
SET #inStr = ?
DECLARE #tmpTable table (tmpID varchar(200))
INSERT #tmptable (tmpID)
SELECT * FROM dbo.splitstring(#inStr)
SELECT id, name, etc
FROM sqlTable
JOIN #tmpTable ON id = tmpID";
$p = array('1,2,100,314');
sqlsrv_query($connection, $q, $p);
I am trying to insert a number of ids into a new table. The list of ids is taken from another table.
My Code:
$stmt = $con->prepare('DROP TABLE tblname;
CREATE TABLE tblname (
id BIGINT
);
INSERT INTO tblname (id)
SELECT tablename2.colname
FROM tablename2
WHERE (col1 = "value" AND col2 = "value")');
$stmt->execute();
I create and dump the table because its part of an update script.
(Is there a better way to do that than dump/create?)
The script needs the current list of ids and I am trying to get create a table with those ids. What happens is, whenever I run the code (using putty) it returns "0" and the table remains empty.
What did I do wrong?
Any general help/advice concerning php/mysql welcome too!
First, make sure PDO is set to throw exceptions if a query fails:
$con->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
Then, perhaps catch the exception (or let the exception halt the application) and see what is wrong.
I do believe your insert query is, erm, off:
INSERT INTO tblname (id)
SELECT tblname2.colname
FROM tablename2
WHERE col1 = "val"
Just seems ambiguous, and messy, even more: it seems unsafe. However, try this -equally messy- query:
INSERT INTO tblname (id) VALUES (
SELECT colname
FROM tblname2
WHERE col1 = "val"
);
Last but not least, make sure you're running PHP version 5.3+, because prior to that version, PDO did not support multiple queries.
My suggestion, though, is not to use multiple queries for the INSERT query. Instead, I'd use a transaction and separate the select and insert query. I'd also add a safety-net to the DROP TABLE and CREATE TABLE queries, too:
try
{
$con->beginTransaction();//DROP & CREATE:
if ($con->exec('DROP TABLE IF EXISTS tblname') === false)
{//query wasn't executed
$con->rollback();
exit($con->errInfo());//error
}
if ($con->exec('CREATE TABLE IF NOT EXISTS tblname(...);') === false)
{
$con->rollback();
exit($con->errInfo());
}
$con->commit();//alter tables.
$con->beginTransaction();//INSERT TRANSACTION
$stmt = $con->prepare('INSERT INTO tblname (id) VALUES (:id)');
$bind = array(
':id' => null
);
$select = $con->prepare(
'SELECT colname FROM tblname2 WHERE col1 = :val1 AND col2 = :val2'
);
$select->execute(
array(
':val1' => 'value1',
':val2' => 'value2'
)
);
while ($row = $select->fetch(PDO::FETCH_ASSOC))
{
$bind[':id'] = $row['colname'];
$stmt->execute($bind);//inserts row
$stmt->closeCursor();//optional
}
$con->commit();//save changes to db
}
catch (PDOException $e)
{
//rollback transaction
$con->rollback();
exit($e->getMessage());//show what went wrong, and exit.
}
You are missing a keyword here to INSERT the value into the table, which is VALUES.
The correct syntax will be
INSERT INTO tblname (id) VALUES
SELECT tablename2.colname
FROM tablename2
WHERE (col1 = 'value' AND col2 = 'value')
The values should be into SINGLE QUOTES, tried and test myself and these 2 work for me every time.!
Since MySQL evidently cannot automatically insert the function now() in a datetime field in adding new records like some other databases, based on comments, I'm explicitly trying to insert it using an SQL statement. (People seem to think timestamp with curdate() is not the answer due to the various limitations of timestamp.) There are numerous articles on the web suggesting inserting now() using SQL should work.
When I try to insert the date time using the SQL statement, however, the field does not populate with the current time/date, but it only gives me the default 0000-00-, etc. This is probably a syntax error, but it's driving me crazy, so I am posting it.
mysql_query("INSERT INTO users (first, last, whenadded) VALUES ('$first', '$last', now())";
It inserts first and last, but nothing for when added, leaving 0000-00-00, etc. in the whenadded field.
The field type is datetime, it has no collation, attributes, null default or extra. BTW, I tried putting now() in single quotes... It threw an error.
NOW() normally works in SQL statements and returns the date and time. Check if your database field has the correct type (datetime). Otherwise, you can always use the PHP date() function and insert:
date('Y-m-d H:i:s')
But I wouldn't recommend this.
You forgot to close the mysql_query command:
mysql_query("INSERT INTO users (first, last, whenadded) VALUES ('$first', '$last', now())");
Note that last parentheses.
Like Pekka said, it should work this way. I can't reproduce the problem with this self-contained example:
<?php
$pdo = new PDO('mysql:host=localhost;dbname=test;charset=utf8', 'localonly', 'localonly');
$pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
$pdo->setAttribute(PDO::ATTR_EMULATE_PREPARES, false);
$pdo->exec('
CREATE TEMPORARY TABLE soFoo (
id int auto_increment,
first int,
last int,
whenadded DATETIME,
primary key(id)
)
');
$pdo->exec('INSERT INTO soFoo (first,last,whenadded) VALUES (0,1,Now())');
$pdo->exec('INSERT INTO soFoo (first,last,whenadded) VALUES (0,2,Now())');
$pdo->exec('INSERT INTO soFoo (first,last,whenadded) VALUES (0,3,Now())');
foreach( $pdo->query('SELECT * FROM soFoo', PDO::FETCH_ASSOC) as $row ) {
echo join(' | ', $row), "\n";
}
Which (currently) prints
1 | 0 | 1 | 2012-03-23 16:00:18
2 | 0 | 2 | 2012-03-23 16:00:18
3 | 0 | 3 | 2012-03-23 16:00:18
And here's (almost) the same script using a TIMESTAMP field and DEFAULT CURRENT_TIMESTAMP:
<?php
$pdo = new PDO('mysql:host=localhost;dbname=test;charset=utf8', 'localonly', 'localonly');
$pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
$pdo->setAttribute(PDO::ATTR_EMULATE_PREPARES, false);
$pdo->exec('
CREATE TEMPORARY TABLE soFoo (
id int auto_increment,
first int,
last int,
whenadded TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
primary key(id)
)
');
$pdo->exec('INSERT INTO soFoo (first,last) VALUES (0,1)');
$pdo->exec('INSERT INTO soFoo (first,last) VALUES (0,2)');
sleep(1);
$pdo->exec('INSERT INTO soFoo (first,last) VALUES (0,3)');
foreach( $pdo->query('SELECT * FROM soFoo', PDO::FETCH_ASSOC) as $row ) {
echo join(' | ', $row), "\n";
}
Conveniently, the timestamp is converted to the same datetime string representation as in the first example - at least with my PHP/PDO/mysqlnd version.
The only reason I can think of is you are adding it as string 'now()', not function call now().
Or whatever else typo.
SELECT NOW();
to see if it returns correct value?
Currently, and with the new versions of Mysql can insert the current date automatically without adding a code in your PHP file. You can achieve that from Mysql while setting up your database as follows:
Now, any new post will automatically get a unique date and time.
Hope this can help.
What about SYSDATE() ?
<?php
$db = mysql_connect('localhost','user','pass');
mysql_select_db('test_db');
$stmt = "INSERT INTO `test` (`first`,`last`,`whenadded`) VALUES ".
"('{$first}','{$last}','SYSDATE())";
$rslt = mysql_query($stmt);
?>
Look at Difference between NOW(), SYSDATE() & CURRENT_DATE() in MySQL for more info about NOW() and SYSDATE().
now()
worked for me .
but my field type is date only and yours is datetime. i am not sure if this is the case
These both work fine for me...
<?php
$db = mysql_connect('localhost','user','pass');
mysql_select_db('test_db');
$stmt = "INSERT INTO `test` (`first`,`last`,`whenadded`) VALUES ".
"('{$first}','{$last}','NOW())";
$rslt = mysql_query($stmt);
$stmt = "INSERT INTO `users` (`first`,`last`,`whenadded`) VALUES ".
"('{$first}', '{$last}', CURRENT_TIMESTAMP)";
$rslt = mysql_query($stmt);
?>
Side note: mysql_query() is not the best way to connect to MySQL in current versions of PHP.
Just go to the column whenadded and change the default value to CURRENT_TIMESTAMP
I've got my database set up with three tables - code, tags, and code_tags for tagging posts.
This will be the SQL query processed when a post is submitted. Each tag is sliced up by PHP and individually inserted using these queries.
INSERT IGNORE INTO tags (tag) VALUES ('$tags[1]');
SELECT tags.id FROM tags WHERE tag = '$tags[1]' ORDER BY id DESC LIMIT 1;
INSERT INTO code_tags (code_id, tag_id) VALUES ($codeid, WHAT_GOES_HERE?)
The WHAT_GOES_HERE? value at the end is what I need to know. It needs to be the ID of the tag that the second query fetched. How can I put that ID into the third query?
I hope I explained that correctly. I'll rephrase if necessary.
Edit: Thanks for your help so far but I'm still struggling a bit in regards to what was pointed out - if it's already there I can't get the inserted ID...?
If you use INSERT IGNORE and a new record is ignored (because of a unique key violation) mysql_insert_id() and LAST_INSERT_ID() don't have a meaningful value.
But you can use INSERT ... ON DUPLICATE KEY UPDATE and LAST_INSERT_ID(expr) to set the data you expect LAST_INSERT_ID() to return in case of a doublet.
Step-by-step:
Let's assume you have a table tags like
CREATE TABLE tags (
id int auto_increment,
tag varchar(32),
dummy int NOT NULL DEFAULT 0, /* for demo purposes only */
primary key(id),
unique key(tag)
)
Inserting a tag twice results in a duplicate key violation because of unique key(tag). That's probably the reason why you've used INSERT IGNORE. In that case MySQL ignores the violation but the new record is ignored as well. The problem is that you want the id of the record having tag='xyz' regardless of whether it has been newly created or it was already in the database. But right now mysql_insert_id()/LAST_INSERT_ID() can oly provide the id of a new record, not an ignored one.
With INSERT ...ON DUPLICATE you can react on such duplicate key violations. If the new record can be inserted (no violation) it behaves like a "normal" INSERT. But in case of a duplicate key violation the part after ON DUPLICATE KEY is executed like an UPDATE statement for the record with that particular index value already existing in the table. E.g. (with an empty table tags)
INSERT INTO tags (tag) VALUES ('tag A') ON DUPLICATE KEY UPDATE dummy=dummy+1
This will simply insert the record as if there was no ON DUPLICATE ... clause. id gets the next auto-increment value, dummy the default value of 0 and tag='tag A'. Let's assume the newly create auto_increment value was 1. The resulting record stored in MySQL is (id=1, tag='tag A', dummy=0) and LAST_INSERT_ID() will return 1 right after this query. So far so good.
Now if you insert the same record again with the same query a violation occurs because of the first record (id=1, 'tag=tag A', dummy=0). For this already exisitng record the UPDATE statement after ON DUPLICATE KEY is executed, i.e. the record becomes (id=1, tag='tag A', dummy=1). But since no new record has been created there was also no new auto_increment value and LAST_INSERT_ID() becomes meaningless. So still the same problem as with INSERT IGNORE.
But there is a "special" construct that allows you to set the value LAST_INSERT_ID() is supposed to return after the ON DUPLICATE KEY UPDATE statement has been executed.
id=LAST_INSERT_ID(id)
Looks strange but it really only sets the value LAST_INSERT_ID() will return.
If you use the statement
INSERT INTO
tags
(tag)
VALUES
('xyz')
ON DUPLICATE KEY UPDATE
id=LAST_INSERT_ID(id)
LAST_INSERT_ID() will always return the id of the record having tag='xyz' no matter if it was added by the INSERT part or "updated" by the ON DUPLICATE KEY part.
I.e. if your next query is
INSERT INTO
code_tags
(code_id, tag_id)
VALUES
(4711, LAST_INSERT_ID())
the tags.id for the tag 'xyz' is used.
The self-contained example script uses PDO and prepared statements. It should do more or less what you want to achieve.
$pdo = new PDO("mysql:host=localhost;dbname=test", 'localonly', 'localonly');
$pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
// set up temporary table and demo data
$pdo->exec('CREATE TEMPORARY TABLE tmpTags (id int auto_increment, tag varchar(32), primary key(id), unique key(tag))');
$pdo->exec('CREATE TEMPORARY TABLE tmpCode_tags (code_id int, tag_id int)');
$pdo->exec("INSERT INTO tmpTags (tag) VALUES ('tagA'), ('tagB')");
// prepare the statements
// set id=LAST_INSERT_ID(id), so LAST_INSERT_ID() gets a value even if the record is "ignored"
$stmtTags = $pdo->prepare('
INSERT INTO
tmpTags
(tag)
VALUES
(:tag)
ON DUPLICATE KEY UPDATE
id=LAST_INSERT_ID(id)
');
$stmtTags->bindParam(':tag', $tag);
$stmtCodeTags = $pdo->prepare('INSERT INTO tmpCode_tags (code_id, tag_id) VALUES (:codeid, LAST_INSERT_ID())');
$stmtCodeTags->bindParam(':codeid', $codeid);
// and some new records we want to insert
$testdata = array(
array('codeid'=>1, 'tags'=>'tagA tagC'), // tagA is already in the table "tags", tagC is a "new" tag
array('codeid'=>2, 'tags'=>'tagC tagD tagE') // tagC will already be inserted, tagD and atgE are "new"
);
// process (test)data
foreach($testdata as $data) {
// the parameter :codeid of $stmtCodeTags is bound to $codeid; assign it the "current" value
$codeid = $data['codeid'];
// split the tags
$tags = explode(' ', $data['tags']);
foreach($tags as $tag) {
// the parameter :tag is bound to $tag
// nothing more to do than to execute the statement
$stmtTags->execute();
// the parameter :codeid is bound to $codeid which was set to $codeid=$data['codeid']
// again nothing more to do than to execute the statement
$stmtCodeTags->execute();
}
}
unset($stmtTags);
unset($stmtCodeTags);
// let's see what we've got
$query = '
SELECT
ct.code_id, t.tag
FROM
tmpCode_tags as ct
JOIN
tmpTags as t
ON
ct.tag_id=t.id
';
foreach( $pdo->query($query, PDO::FETCH_NUM) as $row ) {
echo join(', ', $row), "\n";
}
prints
1, tagA
1, tagC
2, tagC
2, tagD
2, tagE
edit2: In case the PDO-part of the script and the prepared statements are intimidating, here's the same thing using the old php-mysql module. But I urge you to use parametrized prepared statements. Doesn't have to be PDO but I happen to like it. E.g. the mysqli module provides prepared statements as well, the old mysql module doesn't.
$mysql = mysql_connect('localhost', 'localonly', 'localonly') or die(mysql_error());
mysql_select_db('test', $mysql) or die(mysql_error());
// set up temporary table and demo data
mysql_query('CREATE TEMPORARY TABLE tmpTags (id int auto_increment, tag varchar(32), primary key(id), unique key(tag))', $mysql) or die(mysql_error());
mysql_query('CREATE TEMPORARY TABLE tmpCode_tags (code_id int, tag_id int)', $mysql) or die(mysql_error());
mysql_query("INSERT INTO tmpTags (tag) VALUES ('tagA'), ('tagB')", $mysql) or die(mysql_error());
// and some new records we want to insert
$testdata = array(
array('codeid'=>1, 'tags'=>'tagA tagC'), // tagA is already in the table "tags", tagC is a "new" tag
array('codeid'=>2, 'tags'=>'tagC tagD tagE') // tagC will already be inserted, tagD and atgE are "new"
);
// "prepare" the statements.
// This is nothing like the server-side prepared statements mysqli and pdo offer.
// we have to insert the parameters into the query string, i.e. the parameters must
// be escaped so that they cannot mess up the statement.
// see mysql_real_escape_string() for string literals within the sql statement.
$qsTags = "
INSERT INTO
tmpTags
(tag)
VALUES
('%s')
ON DUPLICATE KEY UPDATE
id=LAST_INSERT_ID(id)
";
$qsCodeTags = "
INSERT INTO
tmpCode_tags
(code_id, tag_id)
VALUES
('%s', LAST_INSERT_ID())
";
foreach($testdata as $data) {
// in this example codeid is a simple number
// let's treat it as a string literal in the statement anyway
$codeid = mysql_real_escape_string($data['codeid'], $mysql);
$tags = explode(' ', $data['tags']);
foreach($tags as $tag) {
// now $tag is certainly a string parameter
$tag = mysql_real_escape_string($tag, $mysql);
$query = sprintf($qsTags, $tag);
mysql_query($query, $mysql) or die(mysql_error());
$query = sprintf($qsCodeTags, $codeid);
mysql_query($query, $mysql) or die(mysql_error());
}
}
// let's see what we've got
$query = '
SELECT
ct.code_id, t.tag
FROM
tmpCode_tags as ct
JOIN
tmpTags as t
ON
ct.tag_id=t.id
';
$result = mysql_query($query, $mysql) or die(mysql_error());
while ( false!==($row=mysql_fetch_row($result)) ) {
echo join(', ', $row), "\n";
}
If I understand what you're attempting to achieve correctly, the second query is un-necessary - use mysql_insert_id to obtain the ID of previously inserted row, which is I presume what you need for "WHAT_GOES_HERE".