Perl concatenation for SQL query - sql

I'm trying to transfer the content of a CSV file into a table in PostgreSQL using Perl.
I'm able to update my table successfully, but the terminal returns an error:
Use of uninitialized value in concatenation (.) or string
Syntax error near ","
INSERT INTO test VALUES (, '', '', '', '',, )
Here is the code where it fails :
for (my $i=0 ; $i<=50; $i++){
$dbh ->do("INSERT INTO test VALUES ('$LastName[$i]', '$Street[$i]', $Balance_account[$i])") ;
If more information is needed just ask them.
Sorry for the bad English.
--
Thomas

Use placeholders,
for (my $i=0 ; $i<=50; $i++){
$dbh->do("INSERT INTO test VALUES (?,?,?)",
undef,
$LastName[$i], $Street[$i], $Balance_account[$i]
);
}
Ideally, you should prepare the query and execute for each set of values, something like this:
my $sth = $dbh->prepare('INSERT INTO test VALUES (?,?,?)');
for (my $i=0 ; $i<=50; $i++){
$sth->execute($LastName[$i], $Street[$i], $Balance_account[$i]);
}

My guess is that your error is being caused by not specifying the column names in your insert, while simultaneously having the wrong number/types of columns. I would expect the following Perl code to not error out:
for (my $i=0 ; $i<=50; $i++){
$dbh -> do("INSERT INTO test (lastname, street, balance) VALUES ('$LastName[$i]', '$Street[$i]', $Balance_account[$i])");
Here is what a working query might look like:
INSERT INTO test (lastname, street, balance)
VALUES
('Skeet', '100 Thatcher Street', 100.50);
It is generally considered bad practice to not include column names while doing an insert, because even if you get it right, it could easily break later on.

Related

[ODBC Microsoft Access Driver]COUNT field incorrect

$q = 'INSERT INTO MyTable(proddesc, qnty, PriceH, PriceA, PriceL) VALUES(?,?,?,?,?)';
$sth = odbc_prepare($dbConn, $q);
$success = odbc_execute($sth, array(my 5 variables that are not null));
It gives me the above error - [ODBC Microsoft Access Driver] COUNT field incorrect. I know that the query is correct because I ran it in Access and it was fine. I think I may be using the prepare/execute statements incorrectly.
I also encountered this now and the solution I did to fix it is to quote the variables properly.
Try printing your $q and you will see if it needs to be quoted.
You can try these too:
INSERT INTO TABLE -- quote db and table names using (`) "grave accent" character
VALUES( 'Fed''s' ) -- quote the apostrophes

inserting data from perl into mysql

I'm trying to insert data produced by perl into an oracle database table using perl DBI. Its the first time I've tried this so its likely I'm making a simple mistake.
What i'm using at the moment is:
$dbh = DBI->connect ('dbi:Oracle:geosgen','student','train')
|| die "Database connection not made: $DBI::errstr";
$sql = "INSERT INTO MYTEST VALUES ($series, $sheet, $maxlat, $minlat, $maxlong, $minlong)";
$create = $dbh->do($sql);
print "Content-type:text/html\n\n\n";
if($Create){
print "Success";
}
else{
print "Failure<br/>$DBI::errstr";
}
and the output I get is like this:
DBD::Oracle::db do failed: ORA-00917: missing comma (DBD ERROR: error possibly near <*> indicator at char 36 in 'INSERT INTO MYTEST VALUES (Scotland <*>one inch 1st, Shetland Islands (North) (131), -0.6800, -1.4100, 60.9700, 60.6900)') [for Statement "INSERT INTO MYTEST VALUES (Scotland one inch 1st, Shetland Islands (North) (131), -0.6800, -1.4100, 60.9700, 60.6900)"] at bruce1.pl line 69, <INPUT> line 924.
Content-type:text/html
meaning it has read the data in successfully but failed. I expect I've made a rookie error, is there anything obvious?
SQL requires alphabetic constants to be quoted:
INSERT INTO MYTEST VALUES ('Scotland one inch 1st', 'Shetland Islands (North) (131)', -0.6800, -1.4100, 60.9700, 60.6900)
If you print the value of $sql, you will see that they aren't.

Regex capturing inside a group

I working on a method to get all values based on a SQL query and then scape them in php.
The idea is to get the programmer who is careless about security when is doing a SQL query.
So when I try to execute this:
INSERT INTO tabla (a, b,c,d) VALUES ('a','b','c',a,b)
The regex needs to capture 'a' 'b' 'c' a and b
I was working on this a couple of days.
This was as far I can get with 2 regex querys, but I want to know if there is a better way to do:
VALUES ?\((([\w'"]+).+?)\)
Based on the previous SQL this will match:
VALUES ('a','b','c',a,b)
The second regex
['"]?(\w)['"]?
Will match
a b c a b
Previously removing VALUES, of course.
This way will match a lot of the values I gonna insert.
But doesn't work with JSON for example.
{a:b, "asd":"ads" ....}
Any help with this?
First, I think you should know that SQL support many types of single/double quoted string:
'Northwind\'s category name'
'Northwind''s category name'
"Northwind \"category\" name"
"Northwind ""category"" name"
"Northwind category's name"
'Northwind "category" name'
'Northwind \\ category name'
'Northwind \ncategory \nname'
to match them, try with these patterns:
"[^\\"]*(?:(?:\\.|"")[^\\"]*)*"
'[^\\']*(?:(?:\\.|'')[^\\']*)*'
combine patterns together:
VALUES\s*\(\s*(?:"[^\\"]*(?:(?:\\.|"")[^\\"]*)*"|'[^\\']*(?:(?:\\.|'')[^\\']*)*'|\w+)(?:\s*,\s*(?:"[^\\"]*(?:(?:\\.|"")[^\\"]*)*"|'[^\\']*(?:(?:\\.|'')[^\\']*)*'|\w+))*\)
PHP5.4.5 sample code:
<?php
$pat = '/\bVALUES\s*\((\s*(?:"[^\\"]*(?:(?:\\.|"")[^\\"]*)*"|\'[^\\\']*(?:(?:\\.|\'\')[^\\\']*)*\'|\w+)(?:\s*,\s*(?:"[^\\"]*(?:(?:\\.|"")[^\\"]*)*"|\'[^\\\']*(?:(?:\\.|\'\')[^\\\']*)*\'|\w+))*)\)/';
$sql_sample1 = "INSERT INTO tabla (a, b,c,d) VALUES ('a','b','c',a,b)";
if( preg_match($pat, $sql_sample1, $matches) > 0){
printf("%s\n", $matches[0]);
printf("%s\n\n", $matches[1]);
}
$sql_sample2 = 'INSERT INTO tabla (a, b,c,d) VALUES (\'a\',\'{a:b, "asd":"ads"}\',\'c\',a,b)';
if( preg_match($pat, $sql_sample2, $matches) > 0){
printf("%s\n", $matches[0]);
printf("%s\n", $matches[1]);
}
?>
output:
VALUES ('a','b','c',a,b)
'a','b','c',a,b
VALUES ('a','{a:b, "asd":"ads"}','c',a,b)
'a','{a:b, "asd":"ads"}','c',a,b
If you need to get each value from result, split by , (like parsing CSV)
I hope this will help you :)

Delphi SQL insert into statement error

qryreg.SQL.Add('Insert into RegistreerTB');
qryreg.SQL.add('Name , Surname, E-mail, Password)');
qryreg.SQL.Add('Values ('+quotedstr(edtname.Text)+','+quotedstr(edtsname.Text)+','+quotedstr(edtemail.Text)+','+quotedstr(edtpassuse.Text)+')');
qryreg.ExecSQL ;
qryreg.SQL.Text := 'Select * from RegistreerTB';
qryreg.Open ;
This is the code im using atm with delphi im trying to save data to my database from editboxes. The error im getting is EOELeException "Insert into statement"
ty in advance
As oodesigner stated, a better method would be to use parameters. I don't know what text book you are looking at, but the code given isn't really best practice (it isn't worst practice either, at least it uses QuotedStr rather than '''' + edtname.Text + '''' which fails the first time you use something like O'Connell, and allows SQL injection attacks.
Using parameters and assuming SQL Server syntax as per Rob's answe, and assuming TADOQuery (based on the EOLEException) the code would be something like:
qryreg.SQL.Add('Insert into RegistreerTB');
qryreg.SQL.Add('(Name , Surname, [E-mail], Password)'); //SQL Server syntax with square brackets
// OR qryreg.SQL.Add('(Name , Surname, "E-mail", Password)'); //Oracle/Postgres syntax with double quotes
// OR qryreg.SQL.Add('(Name , Surname, `E-mail`, Password)'); //MySQL syntax with grave accent
qryreg.SQL.Add('Values :Name, :Surname, :Email, :Password)');
qryreg.Parameters.ParamByName('Name').Value := edtName.Text;
qryreg.Parameters.ParamByName('Surname').Value := edtSName.Text;
qryreg.Parameters.ParamByName('Email').Value := edtEmail.Text;
qryreg.Parameters.ParamByName('Password').Value := edtPassUse.Text;
qryreg.ExecSQL;
qryreg.SQL.Text := 'Select * from RegistreerTB';
qryreg.Open ;
As John's answer points out, you need to have parentheses around the column names before VALUES. You need to make sure all the column names are valid SQL identifiers. If they aren't, as in the case for E-mail, you need to quote or escape them according to your database's syntax rules. For example, MySQL uses grave accents, Microsoft SQL uses brackets, and Oracle and Postgresql use quotation marks.
Your problem is in the first line. I made the correction below. you need an opening parenthesis.
qryreg.SQL.Add('Insert into RegistreerTB (');
qryreg.SQL.Add('Name , Surname, E-mail, Password)');
qryreg.SQL.Add('Values ('+quotedstr(edtname.Text)+','+quotedstr(edtsname.Text)+','+quotedstr(edtemail.Text)+','+quotedstr(edtpassuse.Text)+')');
qryreg.ExecSQL ;
qryreg.SQL.Text := 'Select * from RegistreerTB';
qryreg.Open ;
see if this works
qryreg.SQL.Add("Insert into RegistreerTB (");
qryreg.SQL.Add("Name , Surname, E-mail, Password)");
qryreg.SQL.Add("Values ('"+edtname.Text+"','"+edtsname.Text +"','"+edtemail.Text+"','"+edtpassuse.Text +"')");
qryreg.ExecSQL ;
qryreg.SQL.Text := "Select * from RegistreerTB";
qryreg.Open ;
May be you have to call qryreg.SQL.Clear before your first line.
Why not to use parameters ?

How do I update records only if I find a duplicate or otherwise insert data?

In the code below there is a hash which contains records with fields like name, pid, type and time1.
pid and name are repetitive fields which contain duplicates.
I duplicate found update the fields which need modification
else insert, here name and pid have duplicates (repetitive fields).
The rest are unique. Also I have a unique field while creating the table Serial no. How should I go on? I have done only an insertion in this code. I dont know how to store the retrieved record into an array using Perl. Please guide me.
for my $test11 (sort keys %seen) {
my $test1 = $seen{$test11}{'name'};
my $test2 = $seen{$test11}{'pid'};
my $test3 = $seen{$test11}{'type'};
my $test4 = $seen{$test11}{'time1'};
print "$test11\t$test1$test2$test3$test4\n";
$db_handle = &getdb_handle;
$sth = $dbh->prepare("Select username,pid,sno from svn_log1");
$sth->execute() or die "SQL Error: $DBI::errstr\n";
my $ref = $sth->fetchall_arrayref();
print "hai";
print "****$ref";
$sth = $dbh->prepare("INSERT INTO svn_log1 values('$sno','$test11','$test1','$test4','$test2','$test3')");
$sth->execute() or die "SQL Error: $DBI::errstr\n";
}
I think what you're trying to say is that you don't want to try to insert some data if you already have that name/pid combination in the database, but I can't tell, so I can't help you out there.
However, here are a few things which can clear up your code. First, choose sensible variable names. Second, always, always, always use placeholders in your SQL statements to protect them:
for my $test11 ( sort keys %seen ) {
my $name = $seen{$test11}{'name'};
my $pid = $seen{$test11}{'pid'};
my $type = $seen{$test11}{'type'};
my $time1 = $seen{$test11}{'time1'};
my $dbh = getdb_handle();
my $sth = $dbh->prepare("Select username,pid,sno from svn_log1");
$sth->execute() or die "SQL Error: $DBI::errstr\n";
my $ref = $sth->fetchall_arrayref();
# XXX why are we fetching this data and throwing it away?
$sth = $dbh->prepare("INSERT INTO svn_log1 values(?,?,?,?,?,?)");
$sth->execute( $sno, $test11, $name, $time1, $pid, $type )
or die "SQL Error: $DBI::errstr\n";
}
Assuming that you want to not insert something into the database if "$name" and "$pid" are there (and some cleanup to avoid preparing the same SQL over and over):
my $dbh = getdb_handle();
my $seen_sth = $dbh->prepare( "Select 1 from svn_log1 where username = ? and pid = ?");
# This really needs to be "INSERT INTO svnlog1 (#columns) VALUES (#placeholders)
my $insert_sth = $dbh->prepare("INSERT INTO svn_log1 values(?,?,?,?,?,?)");
for my $test11 ( sort keys %seen ) {
my $name = $seen{$test11}{'name'};
my $pid = $seen{$test11}{'pid'};
my $type = $seen{$test11}{'type'};
my $time1 = $seen{$test11}{'time1'};
$seen_sth->execute($name, $pid) or die "SQL Error: $DBI::errstr\n";
my #seen = $seen_sth->fetchrow_array;
next if $seen[0];
$insert_sth->execute( $sno, $test11, $name, $time1, $pid, $type )
or die "SQL Error: $DBI::errstr\n";
}
That's not quite the way I would write this, but it's fairly clear. I suspect it's not really exactly what you want, but I hope it gets you closer to a solution.
You want to insert some data, but if it exists, then update the existing row?
How do you test that the data already exists in the database? Are you using username and pid?
If so, you may like the change the structure of your database:
ALTER TABLE svn_log1 ADD UNIQUE (username, pid);
This create a composite, and unique index on username and pid. This means that every username/pid combination must be unique.
This allows you to do the following:
INSERT INTO svn_log1 (username, pid, ...) VALUES (?, ?, ...) ON DUPLICATE KEY UPDATE time = NOW();
What database is this?
My feeling is that you want an UPDATE or INSERT query, more commonly known as an UPSERT query.
If this is PostgreSQL you can create an upsert function to handle what you need. See the comments for a decent example. Otherwise, search Stack Overflow for "upsert" and you should find what you need.