How to insert timestampz values in postgresql table using php - php

We have one 2 field in of type 'timestampz' like createdon & updatedon
createdon field is inserted using 'Now()' function of postgresql.
and i need to insert updatedon field by using php.
like i try to insert using 'date( 'Y-m-d H:i:s' , $timestamp );'.
When i try to get updated field is gives me wrong result.
I want to know i want to insert timestampz using php how i can to that.

The following article describes how to implement the timestamp behavior of MySql with Postgres:
http://www.depesz.com/index.php/2008/05/08/mysqls-timestamp-in-postgresql/
It works by creating a trigger:
CREATE OR REPLACE FUNCTION trg_handle_timestamp() RETURNS TRIGGER AS $BODY$
BEGIN
IF NEW.y = OLD.y THEN NEW.y := now(); END IF;
RETURN NEW;
END;
$BODY$ LANGUAGE 'plpgsql';
CREATE TRIGGER trg_handle_timestamp
BEFORE UPDATE ON test FOR EACH ROW EXECUTE PROCEDURE trg_handle_timestamp();

Can't you do something like "UPDATE table SET ..., updatedon = NOW() WHERE ..."?

Related

MySQL stored procedure return value based on parameter

I'm trying to create a stored procedure in MySql where it will return all users based on the gender parameter and here is my code:
DELIMITER $$
USE `my_database`$$
DROP PROCEDURE IF EXISTS `GET_ALL_USERS`$$
CREATE DEFINER=`root`#`localhost` PROCEDURE `GET_ALL_USERS`(IN IN_GENDER CHAR)
COMMENT 'Get All Users'
BEGIN
SELECT
*
FROM
users
WHERE
gender = IN_GENDER;
END$$
DELIMITER;
This code works when the parameter is set to 'f' or 'm'. When the gender param is not set it returns nothing. What i want is if the gender param is not set it will return all users. What value should I set to the gender parameter to get all users? Please help thanks
Off the top of my head, not tested...
Try it like this:
gender LIKE CASE WHEN IN_GENDER='' THEN '%' ELSE IN_GENDER END AS MOD_IN_GENDER;
or like this:
gender LIKE COALESCE(IN_GENDER, '%')

Insert ID field generated from trigger, but not passed along

In MySQL, I have a trigger:
BEGIN
IF (EXISTS(SELECT * FROM devices WHERE device_id = NEW.device_id)) THEN
SET NEW.id = NULL;
ELSE
INSERT INTO objects (object_type) VALUES ('3');
SET NEW.id = LAST_INSERT_ID();
END IF;
END
When this trigger gets a new id (from the objects table) it inserts the id into the id column of the devices table.
When I refer to it (for example with mysql_insert_id(); in PHP), its empty.
How can I return the insert id from the trigger (LAST_INSERT_ID();) to the function in PHP as the mysql_insert_id(); ?
Personally I use stored procedures.
Here is a basic example with PDO:
Code to create the Stored Procedures:
CREATE DEFINER=`user`#`localhost` PROCEDURE `InsertUser`(IN `Input_username` INT, OUT `Out_ID` INT)
LANGUAGE SQL
NOT DETERMINISTIC
CONTAINS SQL
SQL SECURITY DEFINER
COMMENT ''
BEGIN
INSERT INTO users(
username)
VALUES (
Input_username);
SET Out_ID = LAST_INSERT_ID();
SELECT Out_ID;
END
And PHP code:
$insert = "CALL InsertUser(:Input_username,
#Out_ID)";
$bdd = new PDO('mysql:host=localhost;dbname=db-name', 'user', 'password');
$stmt = $bdd->prepare($insert);
$stmt->bindParam(':Input_username', rand(), PDO::PARAM_STR); // to create random name
$stmt->execute();
$tabResultat = $stmt->fetch();
$id_user = $tabResultat['Out_ID'];
var_dump($id_user);
I hope I have helped. :)
This behaviour is by design:
If a stored procedure executes statements that change the value of LAST_INSERT_ID(), the changed value is seen by statements that follow the procedure call.
For stored functions and triggers that change the value, the value is restored when the function or trigger ends, so following statements will not see a changed value.
Workaround 1: Stored Procedures
Unfortunately this introduces a risk of inconsistencies between your table and objects, as insertions could still happen outside of this procedure (this problem could be adressed with convoluted access restrictions on the table)
Workaround 2:
Save the value in a user variable:
CREATE TRIGGER
....
BEGIN
INSERT INTO objects (object_type) VALUES ('3');
SET NEW.id = LAST_INSERT_ID();
SET #myLastInsertID = LAST_INSERT_ID();
END //
INSERT INTO your_table... -- trigger the above
SELECT #myLastInsertID; -- here is your value
Workaround 3:
Simply get the value from object ;)
INSERT INTO your_table... -- trigger the above
SELECT MAX(autoinc_column) FROM objects; -- here is your value!
Workarounds 2 and 3 should be wrapped in a transaction to ensure no-one interferes with #myLastInsertID or object during the process.

Insert, delete, update from a pl/sql script use by PHP

I launch a pl/sql script by a PHP application but I notice when there is either an insert, an update or a delete in the script, the script stops. While there is no problem if I use this script directly in sqldeveloper.
Is there something particular to do in order to use insert, delete, update ?
Thanks
procedure update_nbr_execution
(dem_id in number)
IS
BEGIN
UPDATE BCN_DEMANDE_EXTRACTION
SET nombre_execution = nvl(nombre_execution,0) + 1
WHERE id = dem_id;
END;
In my php file :
$query = "BEGIN
ecrire_requete(:demande_id, :p_nom);
END;";
$stid = oci_parse($conn, $query);
$tabvars = oci_new_collection($conn,'MYTABLETYPE');
oci_bind_by_name($stid, ':p_nom', $tabvars, -1, SQLT_NTY);
oci_bind_by_name($stid, ':demande_id', $_POST['demande_id']);
oci_execute($stid, OCI_DEFAULT);
And update_nbr_execution is call by ecrire_requete.
There is a trigger involve in update_nbr_execution, a field date is automatically update with the fiel nbr_execution. May it come from the trigger ?
Edit : after isolating some part, I'm now getting this error : ORA-04088: error during execution of trigger. So it does come from the trigger which looks like this :
create or replace
TRIGGER BCN_FORMAT_NOM_FICHIER_BI
BEFORE INSERT OR UPDATE ON BCN_DEMANDE_EXTRACTION
REFERENCING NEW AS NEW
FOR EACH ROW
DECLARE
BEGIN
if inserting then
:new.FORMAT_NOM_FICHIER_DONNEES:='bcn_<nom_lot>_<id demande>_<n° version>_<description>_<date>.dat';
:new.FORMAT_NOM_FICHIER_CONTROLE:='bcn_<nom_lot>_<id demande>_<n° version>_<date>.ctr';
:new.FORMAT_NOM_FICHIER_JETON:='bcn_<nom_lot>_<id demande>_<n° version>_<date>.jet';
:new.FORMAT_NOM_FICHIER_ZIP:='bcn_<nom_lot>_<id demande>_<n° version>_<date>';
:new.CREATED_AT:=TO_CHAR(SYSDATE,'DD/MM/YY');
:new.UPDATED_AT:=TO_CHAR(SYSDATE,'DD/MM/YY');
else
:new.UPDATED_AT:=TO_CHAR(SYSDATE,'DD/MM/YY');
end if;
END;
This is probably a date format issue.
If CREATED_AT and UPDATED_AT are both dates, then = TO_CHAR(SYSDATE,'DD/MM/YY')
will convert SYSDATE to a string, and then implicitly convert the string back to a date. The implicit date conversion
depends on NLS_DATE_FORMAT, which is set by each client.
You probably have SQL Developer set to use something like DD/MM/YY, but PHP is using something else. If you just
want to remove the time from SYSDATE, you should use TRUNC(SYSDATE) instead.

Calling MySQL stored procedure in PHP only updates one row

I have a stored procedure in MySQL that should update a column in a table. When I run
CALL recalculate_city_ids();
from a MySQL prompt, the correct number of rows are updated (a few hundred). When I run the command from PHP, only a single row is updated and I get no error.
Here's the PHP:
$con = mysqli_connect('localhost', 'user', 'pass', 'dbname' );
$result = $con->query( 'call recalculate_city_ids()' );
mysql_close($con);
And the SQL for the sproc:
DROP PROCEDURE IF EXISTS recalculate_city_ids;
DELIMITER $$
CREATE PROCEDURE recalculate_city_ids()
READS SQL DATA
BEGIN
DECLARE o_id INT DEFAULT 0;
DECLARE o_latitude FLOAT;
DECLARE o_longitude FLOAT;
DECLARE done INT DEFAULT 0;
DECLARE cur_users CURSOR FOR SELECT id, latitude, longitude FROM user WHERE latitude IS NOT NULL ORDER BY fname;
DECLARE CONTINUE HANDLER FOR NOT FOUND SET done=1;
OPEN cur_users;
users: LOOP
FETCH cur_users INTO o_id, o_latitude, o_longitude;
IF done=1 THEN
LEAVE users;
END IF;
SELECT #closest_city_distance:=fn_distance_cosine(o_latitude, o_longitude, latitude, longitude) AS distance, #closest_city_id:=id AS id FROM category WHERE zone="city" AND active=1 ORDER BY distance LIMIT 1;
UPDATE user SET city_id = IF(#closest_city_distance<=30, #closest_city_id, 0) WHERE id=o_id;
END LOOP users;
CLOSE cur_users;
END
$$
I can run other queries from PHP using mysqli (also tried the mysql object). I'm also unable to create stored procedures from PHP (no error) and had to do that part from a MySQL prompt as well.
PHP and my MySQL prompt are using the same username.
I think that PHP doesn't like it when a query returns multiple result sets. I don't really need to return anything since this is just a glorified UPDATE statement, so I changed my
SELECT #closest_city_distance:=fn_distance_cosine... query to
SELECT fn_distance_cosine(o_latitude, o_longitude, latitude, longitude) as distance,id into closest_city_distance, closest_city_id FROM category WHERE zone="city" AND active=1 ORDER BY distance LIMIT 1;
Since that was the only place a result set was getting returned, eliminating the returned sets fixed the problem.

How UPDATE and SELECT at the same time

I need to update some rows of the tables and then display these rows. Is there a way to do this with one single query and avoid this 2 query ? :
UPDATE table SET foo=1 WHERE boo=2
SELECT * from table WHERE ( foo=1 ) AND ( boo=2 )
In PostgreSQL v8.2 and newer you can do this using RETURNING:
UPDATE table
SET foo=1
WHERE boo=2
RETURNING *
You can use a stored procedure in PL/pgSQL. Take a look at the [docs][1]
Something like this
CREATE FUNCTION run(fooVal int, booVal int)
RETURNS TABLE(fooVal int, booVal int)
AS $$
BEGIN
UPDATE table SET foo = fooVal WHERE boo= booVal;
RETURN QUERY SELECT fooVal, booVal from table WHERE ( foo = fooVal ) AND ( boo = booVal );
END;
$$ LANGUAGE plpgsql;
You will save the roundtrip time for sending another statement. This should not be a performance bottleneck. So short answer: Just use two queries. That's fine and this is how you do it in SQL.
[1]: http://www.postgresql.org/docs/8.4/static/plpgsql.html docs
You can use stored procedure or function. It will contains your queries.

Categories