DELIMITER $$
CREATE DEFINER= 'sports'`#`'%'` PROCEDURE `CheckMembership`(IN BrandId int,
IN Email varchar(128),
IN PhoneNumber varchar(10),
OUT ResponseCode int,
OUT ResponseMessage varchar(256))
BEGIN
declare _count int;
select count(*) from Member where Phone1 = PhoneNumber into _count;
set ResponseCode = 1;
set ResponseMessage = '';
END
Can anyone please help me to resolve this stored procedure as I a new to this and couldnot find any good solution in the internet . All I need to do is to get the count value by running it in php
For one thing, the syntax of the SELECT statement is wrong because the INTO clause is misplaced.
That should follow the SELECT list and come before the FROM keyword. For example:
SELECT COUNT(*) INTO _count
FROM Member
WHERE Phone1 = PhoneNumber ;
Syntax help is available in MySQL Reference Manual: http://dev.mysql.com/doc/refman/5.5/en/select-into.html
I'm not sure if this answers the question you were asking. (It's not at all clear what question you were asking.)
Q: I don't know how to call this stored procedure in a php file to get the answers.
From PHP, I think you would need to use MySQL user-defined variables for the OUT arguments, and retrieve those values with a separate SELECT statement:
As a simple demonstration of a pattern you could use, given the arguments of the procedure as shown in the question:
-- set user defined variables
SELECT #brandid = 'fee', #email = 'fi', #phonenumber = 'fo', #rc := '', #rm := '';
-- execute stored procedure with user-defined variables as arguments
CALL CheckMembership(#brandid, #email, #phonenumber, #rc, #rm);
-- retrieve user-defined variables
SELECT #rc AS ResponseCode, #rm AS ResponseMessage;
To return the "count" value, you could follow the same pattern. Modify the procedure to add another OUT parameter, and then set that to the value of that parameter in the procedure.
(This seems an unnecessary rigmarole, using a stored procedure to return a result which could just as easily be returned by a simple query.)
Related
I'm trying to write a PHP program to update a MySQL table entry according to a phone number. The phone numbers in the database are entered without limitations and are typically formatted in the XXX-XXX-XXXX way, but sometimes have other characters due to typos. In order to ensure the query works every time, I want to remove all non-numeric characters from the entries so that I can compare the entries to phone numbers formatted like XXXXXXXXXX coming from a separate source.
I've done some research and found some solutions but am unsure how to incorporate them into the PHP script. I am fairly new to MySQL and most of the solutions provided user defined MySQL functions and I don't know how to put them into the PHP script and use them with the query I already have.
Here's one of the solutions I found:
CREATE FUNCTION [dbo].[CleanPhoneNumber] (#Temp VARCHAR(1000))
RETURNS VARCHAR(1000) AS BEGIN
DECLARE #KeepValues AS VARCHAR(50)
SET #KeepValues = '%[^0-9]%'
WHILE PATINDEX(#KeepValues, #Temp) > 0
SET #Temp = STUFF(#Temp, PATINDEX(#KeepValues, #Temp), 1, '')
RETURN #Temp
END
And this is the query I need the solution for:
$sql = "SELECT pid AS pid FROM patient_data " .
"WHERE pid = '$pID' AND phone_cell = '$phone_number';";
The query should return the data in the pid column for a single patient, so if the phone number is 1234567890 and the pid is 15, 15 should be returned. I have no output at the moment.
The example function definition is Transact-SQL (i.e. for Microsoft SQL Server), it's not valid MySQL syntax.
A function like this doesn't go "into" the PHP code. The function gets created on the MySQL database as a separate step, similar to creating a table. The PHP code can call (reference) the defined function just like it references builtin functions such as DATE_FORMAT or SUBSTR.
The SELECT statement follows the pattern of SQL that is vulnerable to SQL Injection. Any potentially unsafe values that are incorporated into SQL text must be properly escaped. A better pattern is to use prepared statements with bind placeholders.
As an example of a MySQL function:
DELIMITER $$
CREATE FUNCTION clean_phone_number(as_phone_string VARCHAR(1024))
RETURNS VARCHAR(1024)
DETERMINISTIC
BEGIN
DECLARE c CHAR(1) DEFAULT NULL;
DECLARE i INT DEFAULT 0;
DECLARE n INT DEFAULT 0;
DECLARE ls_digits VARCHAR(20) DEFAULT '0,1,2,3,4,5,6,7,8,9';
DECLARE ls_retval VARCHAR(1024) DEFAULT '';
IF ( as_phone_string IS NULL OR as_phone_string = '' ) THEN
RETURN as_phone_string;
END IF;
SET n := CHAR_LENGTH(as_phone_string);
WHILE ( i < n ) DO
SET i := i + 1;
SET c := SUBSTR(as_phone_string,i,1);
IF ( FIND_IN_SET(c,ls_digits) ) THEN
SET ls_retval := CONCAT(ls_retval,c);
END IF;
END WHILE;
RETURN ls_retval;
END$$
DELIMITER ;
We can execute these statements in the mysql command line client, connected as a user with sufficient privilege, to create the function.
This isn't necessarily the best way to write the function, but it does serve as a demonstration.
Once the function is created, we can reference it a SQL statement, for example:
SELECT t.foo
, clean_phone_number(t.foo)
FROM ( SELECT '1' AS foo
UNION ALL SELECT '1-888-TAXICAB'
UNION ALL SELECT '888-555-1212'
UNION ALL SELECT '+=_-()*&^%$##"''<>?/;:"abc...xyz'
UNION ALL SELECT ''
UNION ALL SELECT NULL
) t
I execute SQL query with Yii2 DAO.
$db->createCommand("
DO $$
DECLARE
rec RECORD;
pos INT := 0;
BEGIN
FOR rec IN (SELECT * FROM table1 WHERE "type" = :t LOOP
UPDATE table1 SET position = pos WHERE id = rec.id;
pos := pos + 2;
END LOOP;
END;
$$ language 'plpgsql'
", [':t' => 0])->execute();
But it fails with error:
SQLSTATE[42P18]: Indeterminate datatype: 7
ERROR: could not determine data type of parameter $1
type column has INT type. I tried to set param type explicitly with [':t' => [0, \PDO::PARAM_INT]]. But the error is still here. If I concatenate the value right into the SQL string, it works, but that's not a solution. :t is only one parameter in this query.
Other simple SQL queries work successfully. This problem exists only for queries with procedures. If I run this query from the DataGrip, it works. But in PHP it fails.
Why does it not work and how can I bind params for such queries?
If you create an actual function and call it, you can pass values as parameters.
But while you execute a DO statement, the function body (enclosed in dollar-quotes $$ in your example) is just a string literal. No parameter passing and nothing returned. You would have to concatenate values as strings into the plpgsql code.
But you don't need either. Use a simple prepared statement instead. Much cheaper than looping anyway:
UPDATE table1 t
SET position = t1.pos
FROM (
SELECT id, (row_number() OVER () - 1) * 2 AS pos
FROM table1
WHERE "type" = :t
) t1
WHERE t.id = t1.id
It's trivial to pass a parameter value now.
Aside: The result is arbitrary, unless you add ORDER BY to the OVER clause. That weakness is in your original, too.
Related:
What are '$$' used for in PL/pgSQL
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.
I am using PostgreSQL 9.1.11.
I need to return result of SELECT to my php script. The invocation in php is like this:
$res = $pdb->getAssoc("SELECT * FROM my_profile();");
The class code to illustrate what is going on in php
public function getAssoc($in_query) {
$res = pg_query($this->_Link, $in_query);
if($res == FALSE) {
return array("dberror", iconv("utf-8", "windows-1251", pg_last_error($this->_Link)));
}
return pg_fetch_all($res);
}
Next comes my function in Postgres. I fully re-create database by dropping in a script when I update any function. (The project is in the early stage of development.) I have little to no experience doing stored procedures.
I get this error:
structure of query does not match function result type
CONTEXT: PL/pgSQL function "my_profile" line 3 at RETURN QUERY )
Trying to write:
CREATE FUNCTION my_profile()
RETURNS TABLE (_nick text, _email text) AS $$
BEGIN
RETURN QUERY SELECT (nick, email) FROM my_users WHERE id = 1;
END;
$$
LANGUAGE 'plpgsql' SECURITY DEFINER;
Table structure is:
CREATE TABLE my_users(
id integer NOT NULL,
nick text,
email text,
pwd_salt varchar(32),
pwd_hash character(128),
CONSTRAINT users_pk PRIMARY KEY (id)
);
When I return 1 column in a table the query works. Tried to rewrite procedure in LANGUAGE sql instead of plpgsql with some success, but I want to stick to plpgsql.
The Postgres 9.1.11, php-fpm I am using is latest for fully updated amd64 Debian wheezy.
What I want to do is to return a recordset containing from 0 to n rows from proc to php in an associative array.
This part is incorrect:
RETURN QUERY SELECT (nick, email) FROM my_users WHERE id = 1;
You should remove the parentheses around nick,email otherwise they form a unique column with a ROW type.
This is why it doesn't match the result type.
#Daniel already pointed out your immediate problem (incorrect use of parentheses). But there is more:
Never quote the language name plpgsql in this context. It's an identifier, not a string literal. It's tolerated for now since it's a wide-spread anti-pattern. But it may be considered a syntax error in future releases.
The SECURITY DEFINER clause should be accompanied by a local setting for search_path. Be sure to read the according chapter in the manual.
Everything put together, it could look like this:
CREATE FUNCTION my_profile()
RETURNS TABLE (nick text, email text) AS
$func$
BEGIN
RETURN QUERY
SELECT m.nick, m.email FROM my_users m WHERE m.id = 1;
END
$func$
LANGUAGE plpgsql SECURITY DEFINER SET search_path = public, pg_temp;
Replace public whit the actual schema of your table.
To avoid possible naming conflicts between OUT parameters in RETURNS TABLE ... and table columns in the SELECT statement I table-qualified column names with the given alias m.
I'm trying to create an SQL procedure where is returns a specified value from the members table.
DELIMITER $$
DROP PROCEDURE IF EXISTS `qrgdev`.`ConfirmMember` $$
CREATE PROCEDURE `qrgdev`.`ConfirmMember` (
check_Username varchar(45),
check_Password varchar(255))
BEGIN
DECLARE intcheckId INTEGER(1);
DECLARE intAccessLevel INTEGER(1) DEFAULT 0;
SELECT id INTO intCheckId FROM members WHERE Username=Check_Username;
IF (intCheckId=0)
SELECT AccessLevel INTO intAccessLevel FROM members WHERE passwrd=check_Password;
ELSE
IF (intCheckId>0) THEN
Update members
Set LastSignIn=CURRENT_TIMESTAMP
Where ID=intCheckId;
SELECT AccessLevel INTO intAccessLevel FROM members WHERE id=intCheckId;
ELSE
Insert into members
(ID, Username, Administrator, Passwrd, LastSignIn)
values
(null, check_Username, 0, null, CURRENT_TIMESTAMP);
END IF;
END IF;
RETURN(intAccessLevel);
END $$
DELIMITER ;
so that i can have php set conditions based on that value
//...
$result = $mysqli->query("Call ConfirmMember($username,$password)");
//...
this started as a function before i learned that php cant call sql functions, its why it still hols return at the bottom and also get the point i want to return the value.
create an SQL procedure where is returns a specified value
There's your biggest problem. Procedures do not return values. Functions return values. OTOH you can pass references to variables as arguments in both procedures and functions - and the procedure/function can change the value.
this started as a function before i learned that php cant call sql functions
Who told you that? It's complete nonsense.
$result = $mysqli->query("Call ConfirmMember($username,$password)");
I assume you've escaped and quoted those variables.
Change PROCEDURE to FUNCTION then invoke it as....
SELECT ConfirmMember($username,$password)