Why do I get syntax error for "INSERT INTO"? - sql

String pName = getStrFromUser("Product name: ");
int price = getIntFromUser("Price: ", false);
String category = getStrFromUser("Category: ");
String description = getStrFromUser("Description: ");
PreparedStatement statement = connection.prepareStatement("INSERT INTO ws.products (name, price, cid, description) VALUES (?, ?, (SELECT ws.categories.cid FROM ws.categories WHERE ws.categories.name LIKE ?), ?)");
statement.setString(1, pName);
statement.setInt(2, price);
statement.setString(3, category);
statement.setString(4, description);
statement.executeUpdate();
I get:
Error encountered: ERROR: syntax error at or near "INSERT INTO ws
What might be the problem?

The subquery inside the VALUES clause looks suspicious. Try rephrasing as an INSERT INTO ... SELECT:
String sql = "INSERT INTO ws.products (name, price, cid, description) ";
sql += "SELECT ?, ?, cid, ? FROM ws.categories WHERE name LIKE ?";
PreparedStatement statement = connection.prepareStatement(sql);
statement.setString(1, pName);
statement.setInt(2, price);
statement.setString(3, description);
statement.setString(4, category);
statement.executeUpdate();

I would recommend insert . . . select:
INSERT INTO ws.products (name, price, cid, description)
SELECT ?, ?, ws.categories.cid, ?
FROM ws.categories
WHERE ws.categories.name LIKE ?;
This will not fix the problem with INSERT, but it will prevent the next problem of a subquery returning more than one row.
My best guess for that problem is that the library you are using only supports SELECT statements. That would be atypical; INSERT is usually allowed.

Related

Setting MAX for Auto Increment ID in SQL Server

I have a table that imports 221 rows from a database table. Whenever I add a row dynamically inside the HTML Table page, I want it to be able to pull the MAX ID, so in this case 221, and add 1 to it, therefore bringing the MR_ID to 222. I need this because each ID must be unique. Whenever I add a row into the table and look at it in the database, it displays as NULL. I have a little something for that, but it doesn't seem to be working. If you need any more code than what I posted, let me know and I will provide it. Thank you!
<?php
$MR_ID = $_POST['MR_ID'];
$MR_Name = $_POST['MR_Name'];
$Buyer_ID = $_POST['Buyer_ID'];
$MR_POC_N = $_POST['MR_POC_N'];
$MR_POC_E = $_POST['MR_POC_E'];
$MR_POC_P = $_POST['MR_POC_P'];
$host="xxxxxxx";
$dbName="xxxx";
$dbUser="xxxxxxxxxxx";
$dbPass="xxxxxxxxx";
$pdo = new PDO("sqlsrv:server=".$host.";Database=".$dbName, $dbUser, $dbPass);
$MR_ID = "Select MAX(MR_ID) + 1 FROM Stage_Rebate_Master";
$sql = "INSERT INTO Stage_Rebate_Master (MR_ID, MR_Name, Buyer_ID, MR_POC_N, MR_POC_E, MR_POC_P) VALUES (?, ?, ?, ?, ?, ?)";
$stmt = $pdo->prepare($sql);
$result = $stmt->execute(array($MR_ID, $MR_Name, $Buyer_ID, $MR_POC_N, $MR_POC_E, $MR_POC_P));
echo json_encode($result);
?>
you can try like this
$sql = "INSERT INTO Stage_Rebate_Master (MR_ID, MR_Name, Buyer_ID, MR_POC_N, MR_POC_E, MR_POC_P) SELECT ISNULL(MAX(MR_ID)+1,1), ?, ?, ?, ?, ? FROM Stage_Rebate_Master";
$stmt = $pdo->prepare($sql);
$result = $stmt->execute(array( $MR_Name, $Buyer_ID, $MR_POC_N, $MR_POC_E, $MR_POC_P));

Plain old sql query for insert in codeigniter?

I've looked all over their docks but they really like to use active records. Can someone please tell me how to do a plain old SQL insert for an INSERT in Codeigniter?
EDIT
And this is for their $this->db object;
It's a good idea to escape your inputs.
$sql = "INSERT INTO `yourtable` VALUES `foo`= ? WHERE `id` = ?";
return $this->db->query($sql, [$bar, $id]);
or for an update
$sql = "UPDATE `yourtable` SET `foo`= ?, `bar` = ? WHERE `id` = ?";
return $this->db->query($sql, [$f, $b, $id]);
Using query:
$this->db->query("INSERT INTO ...");
Using active record:
$data = array(
"attribute" => "value"
);
$this->db->insert("table_name", $data);
References:
https://www.codeigniter.com/userguide2/database/queries.html
https://www.codeigniter.com/userguide2/database/active_record.html

SQL request variable quoting

My MySQL query won't work because of quotes, or missing quotes, but I don't understand how to use it properly. I need some explanations about this:
Perl script writing to .csv file:
open(ECRIRE,">$ARGV[1]") || die ("Impossible de creer le fichier de sortie");
foreach my $key (sort keys %caisse)
{
print ECRIRE "insert into etablissement(code_etablissement,nom, contact_ce_nom, contact_ce_tel, contact_ce_mail) values ($key,$caisse{$key}[0];$caisse{$key}[1];$caisse{$key}[2];$caisse{$key}[3]) on duplicate key update contact_ce_nom=$caisse{$key}[1],contact_ce_tel=$caisse{$key}[2],contact_ce_mail=$caisse{$key}[3];\n";
}
close(ECRIRE);
Bash script executing the SQL request:
$mysql -f -h $db_address -P $db_port -u $db_user -p$db_passwd $db_name < $vtiger_temporary_file_etablissement_clean
Mysql is crying over almost every informations like this one
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 'migrationrh2cepal#mail.com) on duplicate key update contact_ce_no' at line 1
I even tried quoting every variable with single quotes, with the same results...
EDIT : Using DBI for perl
The code now looks like :
foreach my $key (sort keys %caisse)
{
my $insert = $sql_connection->prepare('insert into etablissement values(?, ?, ?, ?, ?, ?) on duplicate key update');
$insert->execute($key, $caisse{$key}[0], $caisse{$key}[1], $caisse{$key}[2], $caisse{$key}[3],'');
}
I now have the "on duplicate key" issue. How can I add the "on duplicate key" statement in here ?
I tried adding it at the end, just like this :
my $insert = $sql_connection->prepare('insert into etablissement values(?, ?, ?, ?, ?, ?) on duplicate key update');
But it's not working
Instead of quoting the variables yourself, use the DBI module and placeholders:
$db = 'DBI'->connect(...);
my $insert = $db->prepare('insert into etablissement values(?, ?, ?)');
$insert->execute($key, $caisse{$key}[0], $caisse{$key}[1]);
For repeated values, numbered placeholders are usually used:
my $insert = $db->prepare(<<'__SQL__');
INSERT INTO etablissement
(code_etablissement, nom, contact_ce_nom, contact_ce_tel, contact_ce_mail)
VALUES (:1, :2, :3, :4, :5)
ON DUPLICATE KEY UPDATE contact_ce_nom = :3,
contact_ce_tel = :4,
contact_ce_mail = :5'
__SQL__
$insert->execute($key, #{ $caisse{$key} }[0 .. 3]);
If your driver doesn't support them (I don't see them mentioned in DBD::mysql), you can workaround it e.g.
my $insert = $db->prepare(<<'__SQL__');
INSERT INTO etablissement
(code_etablissement, nom, contact_ce_nom, contact_ce_tel, contact_ce_mail)
VALUES (?, ?, ?, ?, ?)
ON DUPLICATE KEY UPDATE contact_ce_nom = ?,
contact_ce_tel = ?,
contact_ce_mail = ?
__SQL__
$insert->execute($key, #{ $caisse{$key} }[0 .. 3], #{ $caisse{$key} }[1 .. 3]);
or you can play with quote and omit placeholders totally.
Using partial answer from choroba :
The final question is "how to use on duplicate key syntax with perl DBI ?"
Like this
my $insert = $sql_connection->prepare('insert into etablissement values(?, ?, ?, ?, ?, ?) on duplicate key update contact_ce_nom=?,contact_ce_tel=?,contact_ce_mail=?');
$insert->execute($key, $caisse{$key}[0], $caisse{$key}[1], $caisse{$key}[2], $caisse{$key}[3],'',$caisse{$key}[1],$caisse{$key}[2],$caisse{$key}[3]);
The last 3 ARGS are used by the "on udplicate key" syntax...

insert into two tables at the same time

I have to INSERT INTO two tables at once, let's say one table is my client_enquiry and another table is the client_materials.
Until here it's okay, the INSERT command it's working in both tables. And If something bad happens when I'm inserting on the second table (client_materials)? How can I "rool back" if the INSERT command fails on table client_materials?
Basically I have this:
$sql_table1 = "INSERT INTO client_enquiry (reference, date) VALUES ('REF', '2013-05-12')";
$q = $conn->prepare($sql_table1);
$q ->execute();
$Last_ID = $conn->lastInsertId('id_enquiry');
$sql_table2 = "INSERT INTO client_materials (id_client_enquiry,description, date)
VALUES (".$Last_ID."'Description', '2013-05-12')";
$q = $conn->prepare($sql_table2);
$q -> execute();
Do the very rollback you mentioned.
$conn->beginTransaction();
try
{
$sql = "INSERT INTO client_enquiry (reference, date) VALUES (?,?)";
$q = $conn->prepare($sql);
$q ->execute(array('REF', '2013-05-12'));
$Last_ID = $conn->lastInsertId();
$sql_table2 = "INSERT INTO client_materials (id_client_enquiry,description, date)
VALUES (?,?,?)";
$q = $conn->prepare($sql);
$q -> execute(array($Last_ID, 'Description', '2013-05-12'));
$conn->commit();
}
catch (PDOException $e)
{
$conn->rollback();
throw $e;
}
You just need to be sure that engine supports transactions and PDO is set into exception throwing mode

How can I use placeholders for variadic SQL functions with Perl's DBI?

I don't know if "variadic" is actually the right word, but I'm talking about things that can take a list of values, like IN(). If you've been working with DBI for long, you've probably tried to do this:
(Note: All examples extremely simplified for brevity)
my $vals = join ', ', #numbers;
my $sth = $dbh->prepare( "SELECT * FROM mytbl WHERE foo IN( ? )" );
$sth->execute( $vals ); # doesn't work
DBI placeholders simply don't support these kinds of shenanigans, it's a single value for each ? or nothing, as far as I know.
This leads me to end up doing something like:
my $sth = $dbh->prepare( "SELECT * FROM mytbl WHERE foo IN ( $vals )" );
which isn't so horrible, but consider a function, like one I wrote today, that has to accept some arbitrary SQL with an IN clause and a list of values
sub example {
my $self = shift;
my ( $sql, #args ) = #_;
my $vals = join ', ', #args;
$sql =~ s/XXX/$vals/; <---- # AARRRGHGH
my $sth = $self->dbh->prepare( $sql );
...
}
This ends up getting called by stuff that looks like
my $sql = "SELECT * FROM mytbl WHERE foo IN( XXX ) AND bar = 42 ORDER BY baz";
my $result = $self->example( $sql, #quux );
This really offends my sense of aesthetics. Building custom SQL programmaticly is a big enough pain as it is; I don't want to go down the road of regexing my SQL strings if I don't have to.
Is there a better way?
Food for thought.
DBIx::Simple offers a syntax for this type of thing using a double-question mark placeholder:
$db->query( 'SELECT * FROM mytbl WHERE foo IN ( ?? )', #args );
Also, SQL::Abstract is powerful, but I find sometimes the abstractions don't result in optimal SQL.
Why not:
my $sql = "SELECT * FROM mytbl WHERE foo IN(" . join(',', ('?')x#quux) . ") AND bar = 42 ORDER BY baz";
my $sth = $dbh->prepare($sql);
$sth->execute(#quux);
If you don't mind breaking from pure DBI and using some modules, I'd take a look at SQL::Abstract for your example. SQL::Abstract can take a Perl hash and turn it into a where clause.
my $sql = SQL::Abstract->new;
my #numbers = (1 .. 10);
my ($stmt, #bind) = $sql->where({foo => {'in', \#numbers}});
# $stmt is " WHERE ( foo IN ( ?, ?, ?, ?, ?, ?, ?, ?, ?, ? ) )"
# #bind contains the values 1 through 10.
sprintf is handy in such situations:
my $sth = $dbh->prepare(
sprintf(
'SELECT * FROM mytbl WHERE foo IN( %s )',
join(',', ('?') x #numbers) )
);
If using placeholders and bind values gets clumsy, there's always DBI::quote().
my $sql = sprintf 'SELECT * FROM mytabl WHERE foo IN ( %s )',
join( ',', map { $dbh->quote( $_ ) } #args );