How can I fetch the last row that was inserted using DBI (DBD::mysql)?
Code sample:
my $sth = $dbh->prepare('INSERT INTO a ( x, y, z ) VALUES ( ?, ?, ? )');
$sth->execute( $x, $y, $z );
How can I get access to the data that was inserted by the above prepare statement? I need to get the primary ID (AUTOINCREMENT) value.
UPDATE:
From DBD::mysql documentation:
An alternative way for accessing this
attribute is via
$dbh->{'mysql_insertid'}.
Thank you Manni and n0rd for your answers. :-)
This is a property of the statement handle. You should be able to access the ID like that:
$sth->{mysql_insertid}
A database agnostic approach is to use the DBI's last_insert_id method. This approach helps to reduce dependency on a specific database:
$dbh->last_insert_id
$rv = $dbh->last_insert_id($catalog, $schema, $table, $field);
Returns a value 'identifying' the row just inserted, if possible. Typically this would be a value assigned by the database server to a column with an auto_increment or serial type. Returns undef if the driver does not support the method or can't determine the value.
SELECT LAST_INSERT_ID() query will also return what you want.
Related
I am trying to fetch data like (Select 1 from table) which returns data with one row and one column.
I dont want to use $sth->fetchrow_array method to retreive the data in to array. Is there any way to collect the data into scalar variable direclty?
fetchrow_array returns a list —it's impossible to return an array— and you can assign that to anything list-like such as a my().
my $sth = $dbh->prepare($stmt);
$sth->execute();
my ($var) = $sth->fetchrow_array()
and $sth->finish();
Or you could simply use
my ($var) = $dbh->selectrow_array($stmt);
my ($value) = #{$dbh−>selectcol_arrayref("select 1 from table")}
or better
my ($value) = $dbh−>selectrow_array($statement);
I must to write a UDF returning a Table. I’ve done it with Static SQL.
I’ve created Procedures preparing a Dynamic and Complex SQL sentence and returning a cursor.
But now I must to create a UDF with Dynamic SQL and return a table to be used with an IN clause inside other select.
It is possible on DB2 v5R4? Do you have an example?
Thanks in advance...
I don't have V5R4, but I have i 6.1 and V5R3. I have a 6.1 example, and I poked around in V5R3 to find how to make the same example work there. I can't guarantee V5R4, but this ought to be extremely close. Generating the working V5R3 code into 'Run SQL Scripts' gives this:
DROP SPECIFIC FUNCTION SQLEXAMPLE.DYNTABLE ;
SET PATH "QSYS","QSYS2","SYSPROC","SYSIBMADM","SQLEXAMPLE" ;
CREATE FUNCTION SQLEXAMPLE.DYNTABLE (
SELECTBY VARCHAR( 64 ) )
RETURNS TABLE (
CUSTNBR DECIMAL( 6, 0 ) ,
CUSTFULLNAME VARCHAR( 12 ) ,
CUSTBALDUE DECIMAL( 6, 0 ) )
LANGUAGE SQL
NO EXTERNAL ACTION
MODIFIES SQL DATA
NOT FENCED
DISALLOW PARALLEL
CARDINALITY 100
BEGIN
DECLARE DYNSTMT VARCHAR ( 512 ) ;
DECLARE GLOBAL TEMPORARY TABLE SESSION.TCUSTCDT
( CUSTNBR DECIMAL ( 6 , 0 ) NOT NULL ,
CUSTNAME VARCHAR ( 12 ) ,
CUSTBALDUE DECIMAL ( 6 , 2 ) )
WITH REPLACE ;
SET DYNSTMT = 'INSERT INTO Session.TCustCDt SELECT t2.CUSNUM , (t2.INIT CONCAT '' '' CONCAT t2.LSTNAM) as FullName , t2.BALDUE FROM QIWS.QCUSTCDT t2 ' CONCAT CASE WHEN SELECTBY = '' THEN '' ELSE SELECTBY END ;
EXECUTE IMMEDIATE DYNSTMT ;
RETURN SELECT * FROM SESSION . TCUSTCDT ;
END ;
COMMENT ON SPECIFIC FUNCTION SQLEXAMPLE.DYNTABLE
IS 'UDTF returning dynamic table' ;
And in 'Run SQL Scripts', the function can be called like this:
SELECT t1.* FROM TABLE(sqlexample.dyntable('WHERE STATE = ''TX''')) t1
The example is intended to work over IBM's sample QCUSCDT table in library QIWS. Most systems will have that table available. The table function returns values from two QCUSCDT columns, CUSNUM and BALDUE, directly through two of the table function's columns, CUSTNBR and CUSTBALDUE. The third table function column, CUSTFULLNAME, gets its value by a concatenation of INIT and LSTNAM from QCUSTCDT.
However, the part that apparently relates to the question is the SELECTBY parameter of the function. The usage example shows that a WHERE clause is passed in and used to help built a dynamic 'INSERT INTO... SELECT...statement. The example shows that rows containingSTATE='TX'` will be returned. A more complex clause could be passed in or the needed condition(s) could be retrieved from somewhere else, e.g., from another table.
The dynamic statement inserts rows into a GLOBAL TEMPORARY TABLE named SESSION.TCUSTCDT. The temporary table is defined in the function. The temporary column definitions are guaranteed (by the developer) to match the 'RETURNS TABLE` columns of the table function because no dynamic changes can be made to any of those elements. This allows SQL to handle reliably columns returned from the function, and that lets it compile the function.
The RETURN statement simply returns whatever rows are in the temporary table after the dynamic statement completes.
The various field definitions take into account the somewhat unusual definitions in the QCUSTCDT file. Those don't make great sense, but they're useful enough.
I have a table in a SQLite database where a column stores file mtimes in epoch seconds.
I would now like to search in that table files that were modified in a certain month?
In raw SQL I would do:
select * from my_table where strftime('%Y-%m', mtime, "unixepoch") = "2009-08"
Is there a way to do this efficiently via DBIx::Class? Is it possible to do
$m->search({ \'strftime('%Y-%m', mtime, "unixepoch")' => "2009-08" })
I tried understanding if there's a way with DBIx::Class::InflateColumn::DateTime but I didn't find it.
Thanks
Simone
The syntax you're looking for is:
$m->search(
\[ q{strftime('%Y-%m', mtime, "unixepoch") = ?}, "2009-08" ]
);
Yes, that's an array-ref-ref. The first element is literal SQL which is permitted to use ? placeholders, and the remaining elements are values to bind to those placeholders, and DBIC will make sure to reorder everything internally so that those values get put into the right place in the bind list when the query runs.
If you need to combine one of these with other criteria, since an arrayrefref isn't a valid hash key, you need to use the -and syntax:
$m->search({
-and => [
foo => 'bar',
\[ q{ SQL }, $bind ],
],
});
Here is the section of the SQL::Abstract docs for this construct.
I would suggest you using search_literal instead:
# assuming $m isa DBIx::Class::ResultSet
$m->search_literal('strftime("%Y%m", mtime, "unixepoch") = ?', '200908');
EDIT: I stand corrected. Please refer to #hobbs' comment and answer.
What's wrong with the following Postgres query?
INSERT INTO kayak.airports(name, x, y, city) VALUES( $name, $x, $y, $city)
WHERE airport_id='$airport_id
EDIT (thanks Donnie for helping me make progress) :
I tried:
$query="UPDATE kayak.airports SET name=$name, x = $x, y = $y, city = $city
WHERE airports.airport_id='$airport_id'";
It said "column 'Brisbane' doesn't exist" (Brisbane is the first city to be inserted. ) I took out everything between SET and WHERE except for "x=$x" and those were successfully inserted. Ditto for "y=$y". When only leaving in name=$name it says
"Query failed: ERROR: syntax error at or near "International" LINE 1: UPDATE kayak .airports SET name=Brisbane International WHERE... ^"
Your query string is not quoted. Do not use PHP variable interpolation for building SQL queries, because this will leave your script or application vulnerable to an SQL injection attack.
Instead, use parameterized queries. Thus, your query above becomes:
$query = 'UPDATE kayak.airports SET name = $1, x = $2, y = $3, city = $4'.
'WHERE airports.airport_id = $5';
Then, you will use the parameterized query calling function pg_query_paramsto pass the required parameters:
$result = pg_query_params($query, $parameters)
Where $parameters is an array of parameters.
Also note that the $query string is single-quoted, because the $n placeholders are not there for interpolation. This prevents any mistakes (such as typing a real variable name by bumping a letter first) and eliminates any possibility of SQL injection.
You're attempting to insert literal values. A where clause makes no sense.
For insert, you can only use where in an insert ... select to limit what the select is returning.
Perhaps you actually want to update an existing record?
For me, if I get an error that a column doesn't exist, it's usually a tipoff that I've quoted something incorrectly (or not at all).
This is borne out by the error message from your attempt to update only the name field:
ERROR: syntax error at or near "International" LINE 1:
(The carat should point right to the problem area in the query.)
The value you are passing to the name field in your UPDATE statement needs to be quoted, just like the value you're passing to airport_id. (I'm going to take a wild guess that x and y are integers, which wouldn't require quoting, which is why you don't get an error when you try to update just those field.) (I'm going to take another wild guess that the value you pass to city will need to be quoted too, but you will probably figure that out shortly. :) )
The end result expanded UPDATE should look something like this:
UPDATE kayak.airports
SET name='Brisbane International', x = 123, y = 456, city = 'Brisbane'
WHERE ...
According to ZF documentation when using fetchAssoc() the first column in the result set must contain unique values, or else rows with duplicate values in the first column will overwrite previous data.
I don't want this, I want my array to be indexed 0,1,2,3... I don't need rows to be unique because I won't modify them and won't save them back to the DB.
According to ZF documentation fetchAll() (when using the default fetch mode, which is in fact FETCH_ASSOC) is equivalent to fetchAssoc(). BUT IT'S NOT.
I've used print_r()function to reveal the truth.
print_r($db->fetchAll('select col1, col2 from table'));
prints
Array
(
[0] => Array
(
[col1] => 1
[col2] => 2
)
)
So:
fetchAll() is what I wanted.
There's a bug in ZF documentation
From http://framework.zend.com/manual/1.11/en/zend.db.adapter.html
The fetchAssoc() method returns data in an array of associative arrays, regardless of what value you have set for the fetch mode, **using the first column as the array index**.
So if you put
$result = $db->fetchAssoc(
'SELECT some_column, other_column FROM table'
);
you'll have as result an array like this
$result['some_column']['other_column']