Syntax error in SELECT query inside PHP script - php

I am trying to create a query inside a PDO script that checks if a record exists if it does the query should update the record and if it doesn't exist it should create a new one.
The column that should only exist once in the table is not an INDEX key (cannot make it unique right now) so it is not set as unique and I cannot use the ON DUPLICATE KEY UPDATE
I would like to use this queries logic below to make it work:
$stmt = $conn->prepare('IF EXISTS (SELECT * FROM `Table1` WHERE `code`= :code )
UPDATE `Table1`
SET `code_stat` = 2
WHERE code = :code
ELSE
INSERT INTO `Table1` (`code`,`code_stat`)
VALUES (:code, 2 ) ' );
$stmt->execute([
'code' => $_POST['code']
]);
The problem is when executing the query I get the following error saying there is a syntax problem:
SQL syntax; check the manual that corresponds
to your MySQL server version for the right syntax to use near
'IF EXISTS (SELECT * FROM Table1 WHERE code= ? ) UPDATE Table1' at line 1

If you can't add a unique key to the table, you can attempt an update first, and if that doesn't update any rows, do an insert. Something like this:
$stmt = $conn->prepare('UPDATE `Table1` SET `code_stat` = 2 WHERE code = :code');
$stmt->execute(array(':code' => $_POST['code']));
if (!$stmt->rowCount()) {
// no rows updated, so insert
$stmt = $conn->prepare('INSERT INTO `Table1` (`code_stat`, `code`) VALUES (2, :code)');
$stmt->execute(array(':code' => $_POST['code']));
}
Note that you may need to set the PDO::MYSQL_ATTR_FOUND_ROWS attribute to ensure that the UPDATE query returns 1 if it finds the row but the value doesn't change. You must set that attribute when you make the connection e.g.
$conn = new PDO($dsn, $user, $pass, array(PDO::MYSQL_ATTR_FOUND_ROWS => true));

Why not write a stored procedure to handle this, similar to the below:
DROP PROCEDURE IF EXISTS db.SP_NEW_CODE;
CREATE PROCEDURE db.`SP_NEW_CODE`(IN `in_code` INT)
BEGIN
DECLARE numFound INT DEFAULT 0;
SET numFound=(SELECT * FROM `Table1` WHERE `code`= in_code);
IF (numFound=0) THEN
INSERT INTO `Table1` (`code`,`code_stat`) VALUES (in_code, 2 );
ELSE
UPDATE `Table1` SET `code_stat` = 2 WHERE code = in_code
END IF;
END;
From your code, simple execute CALL SP_NEWCODE(3); (for example, where 3 is the appropriate code value).

Related

Syntax issue writing conditional mySQL query in PHP

I have the following mySQL query written in the format of a PHP PDO script. I made sure to verify that all of the columns I refer to in the query exist.
So the issue seems to do with the syntax of the query itself. When executing the query in POSTMAN I see the issue seems to be where the if statement beings.
The following is the query:
$stmt = $conn->prepare('IF EXISTS (SELECT * `Table1` WHERE `code`= :code )
UPDATE `Table1`
SET `code_stat` = 2
WHERE code = :code
ELSE
INSERT INTO `Table1` (`code`,`code_stat`)
VALUES (:code, 2 ) ' );
$stmt->execute([
'code' => $_POST['code']
]);
Alternative query:
$stmt = $conn->prepare("REPLACE INTO `Table` (`code`,`code_stat`) VALUES (:code,2)");
$stmt->execute(['code' => $_POST['code']);
If the row does not exists, it will be inserted otherwise it will be updated.
https://dev.mysql.com/doc/refman/5.7/en/replace.html
Think you're just missing the ‘FROM’.
SELECT * `Table1` WHERE
should be
SELECT * FROM `Table1` WHERE

PHP PDO fetchAll() returns empty array while SELECTing Temporary Table

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));

Search parameters SQLSRV_QUERY for WHERE IN syntax

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);

select insert into not working

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.!

Update if row exists, otherwise insert new row into another table

I know this question but it didn't help.
I have a list with ids and values. Now I have to check if the id exists in my user database. If it does, then the row will be updated, otherwise I have to insert the id in another table (tmp_user).
Edit: Here is my try
IF NOT EXISTS (SELECT * FROM `wcf1_user` WHERE `steamID` = 1) THEN
INSERT INTO `wcf1_points_tmp` (`steamID`, `points`) VALUES (1, 2)
ELSE
// Update stuff......
END IF;
Result: #1064 - You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'IF NOT EXISTS (SELECT * FROM wcf1_user WHERE steamID = 1) THEN INSERT IN' at line 1
Thanks for your help. :)
If you specify ON DUPLICATE KEY UPDATE, and a row is inserted that would cause a duplicate value in a UNIQUE index or PRIMARY KEY, an UPDATE of the old row is performed. For example, if column a is declared as UNIQUE and contains the value 1, the following two statements have identical effect:
INSERT INTO table (a,b,c) VALUES (1,2,3)
ON DUPLICATE KEY UPDATE c=c+1;
UPDATE table SET c=c+1 WHERE a=1;
This is domain logic, which doesn't belong in the data tier. Do it in PHP instead:
<?php
// connect to the database
$DSN = "mysql:dbname=$dbname;charset=utf8";
$opt = array(PDO::MYSQL_ATTR_FOUND_ROWS => true);
$dbh = new PDO($DSN, $username, $password, $opt);
$dbh->setAttribute(PDO::ATTR_EMULATE_PREPARES, false);
$dbh->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
// one assumes you want to perform this operation atomically
$dbh->beginTransaction();
// attempt to update the row
$update = $dbh->prepare('
UPDATE wcf1_user
SET ......
WHERE steamID = ?
');
$update->execute(array($steamID));
// if the update didn't affect any rows
if (!$update->rowCount()) {
// insert into another table instead
$insert = $dbh->prepare('
INSERT INTO wcf1_points_tmp
(steamID, points)
VALUES
(?, ?)
');
$insert->execute(array($steamID, $points));
}
// tada!
$dbh->commit();
?>
I think you are missing semicolon at the end of insert statement, try following,
IF NOT EXISTS (SELECT * FROM `wcf1_user` WHERE `steamID` = 1) THEN
INSERT INTO `wcf1_points_tmp` (`steamID`, `points`) VALUES (1, 2);
ELSE
// Update stuff...... remember to add semicolon at the end
END IF;

Categories