I'm trying to read an OUTPUT value from a SQL stored procedure using PHP, PDO and Microsoft SQL Server 2008 (SQLSRV), but despite having read several articles on the subject can still not seem to get it working. The stored procedure essentially checks if a record already exists or not, and I want it to return a 1 or a 0 to the PHP depending on what it's found. The value of $retval never gets changed from its originally initialised value of 5, though.
PHP:
// Initialise return value variable as an integer type; this should be changed
// by the returned value from SQL
$retval = 5;
// call the stored procedure
$stmt = $connPDO->prepare('EXEC dbo.EnrollApplicant :applicantID, :retval ');
$stmt->bindParam(':applicantID', $applicantID, SQLSRV_PARAM_IN);
$stmt->bindValue(':retval', $retval, SQLSRV_PARAM_INOUT);
$stmt->execute();
// Return values to AJAX
echo json_encode(array(
"RowCount" => $stmt->rowCount(),
"PDOErrors" => $stmt->errorInfo(),
"InsertID" => $connPDO->lastInsertID(),
"applicantID" => $applicantID,
"retval" => $retval
));
SQL:
USE [MScPublicDev]
GO
/****** Object: StoredProcedure [dbo].[EnrollApplicant] Script Date: 11/19/2015 10:31:10 ******/
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
ALTER Procedure [dbo].[EnrollApplicant] #APPID INT, #retval int OUTPUT AS
SELECT #APPID
DECLARE #surname AS nvarchar(50)
DECLARE #forename AS nvarchar(50)
DECLARE #studentID AS nvarchar(25)
DECLARE #studentID1 AS nvarchar(100)
SET #surname = (SELECT upper(Surname) FROM Applicant WHERE ID = #APPID )
SET #forename = (SELECT upper(Forename) FROM Applicant WHERE ID = #APPID )
SET #studentID1 = #surname + ', ' + #forename
SELECT #studentID1
SET #studentID = (SELECT dbo.GenerateStudentID (#studentID1))
SELECT #studentID AS StudentID
DECLARE #found AS int
SET #found = (SELECT COUNT(*) FROM Student WHERE Surname = #surname and Forename = #forename)
If #found = 0
BEGIN
-- TSQL to Insert Student record from Applicant record details goes here
SELECT * FROM Student WHERE StudentID = #studentID
END
#retval = #found
GO
Related
Info:
PHP 7.0.0
SQL Server 2014
Using sqlsrv driver
The following code may not be optimal but this is the PHP:
$nombre = strval($info->nombre);
$idPerfil = 0;
$sqlAltaPerfil = "{CALL AltaPerfil(?,?)}";
$paramsAltaPerfil = [
[$nombre, SQLSRV_PARAM_IN, SQLSRV_PHPTYPE_STRING(SQLSRV_ENC_CHAR), SQLSRV_SQLTYPE_VARCHAR(50)],
[&$idPerfil, SQLSRV_PARAM_INOUT, SQLSRV_PHPTYPE_INT, SQLSRV_SQLTYPE_INT]
];
$stmtAltaPerfil = sqlsrv_query($conexion, $sqlAltaPerfil, $paramsAltaPerfil);
if($stmtAltaPerfil !== false) {
sqlsrv_next_result($stmtAltaPerfil);
$sqlAltaPerfilXExComp = "{CALL AltaPerfilXExamenComplementario(?, ?)}";
foreach($info->arrayIdExComp as $idExComp){
$idExComp = intval($idExComp);
var_dump($idExComp);
$paramsAltaPerfilXExComp = [
[$idPerfil, SQLSRV_PARAM_IN, SQLSRV_PHPTYPE_INT, SQLSRV_SQLTYPE_INT],
[$idExComp, SQLSRV_PARAM_IN, SQLSRV_PHPTYPE_INT, SQLSRV_SQLTYPE_INT]
];
$stmtAltaPerfilXExComp = sqlsrv_query($conexion, $sqlAltaPerfilXExComp, $paramsAltaPerfilXExComp);
if($stmtAltaPerfilXExComp !== false){
//bien
}
else{
$exito = false;
$erroresPhp .= print_r(sqlsrv_errors(), true);
break;
}
}
}
This is the SP:
ALTER PROCEDURE [dbo].[AltaPerfil](
#Descripcion varchar(50),
#IdPerfil int OUTPUT
) AS
BEGIN
INSERT INTO PERFILEXAMENCOMPLEMENTARIO (Descripcion) VALUES (#Descripcion)
SET #IdPerfil = ##IDENTITY
RETURN
END
I know by the error message i display in the client side that $idPerfil remains equal to 0 (line 2). The fun fact is that in SSMS the SP works just fine, but when calling it from PHP the $idPerfil isn't modified
EDIT: I found that the problem is not the code, it's a trigger in the DB that
for some reason interferes with the ##IDENTITY variable in the SP.
This is the trigger:
ALTER TRIGGER [dbo].[NombresPerfilesUnicos] ON [dbo].[PERFILEXAMENCOMPLEMENTARIO] INSTEAD OF INSERT, UPDATE AS
BEGIN
DECLARE #NombrePerfil varchar(50)
SELECT #NombrePerfil = Descripcion FROM inserted
IF EXISTS(SELECT PEC.IdPerfil FROM PERFILEXAMENCOMPLEMENTARIO PEC WHERE Descripcion = #NombrePerfil)
PRINT 'ERROR, la descripcion ' + #NombrePerfil + ' ya esta registrada'
else
INSERT INTO PERFILEXAMENCOMPLEMENTARIO SELECT Descripcion FROM inserted
END
So my new question is: Why this is happening? What do i have to do to keep this trigger working (modify if necessary) and make everything work?
Try using SCOPE_IDENTITY() instead of ##Identity.
Sourced from :
http://blog.sqlauthority.com/2007/03/25/sql-server-identity-vs-scope_identity-vs-ident_current-retrieve-last-inserted-identity-of-record/
"SELECT ##IDENTITY
It returns the last IDENTITY value produced on a connection, regardless of the table that produced the value, and regardless of the scope of the statement that produced the value."
"SELECT SCOPE_IDENTITY()
It returns the last IDENTITY value produced on a connection and by a statement in the same scope, regardless of the table that produced the value."
You can use in the following way: and you don't need second variable if you don't have any transaction with that next in the stored procedure.Using IDENT_CURRENT with table name is much better than others because it just return you identity value of mentioned table.
--Procedure Part
ALTER PROCEDURE [dbo].[AltaPerfil](
#Descripcion VARCHAR(50)
) AS
BEGIN
INSERT INTO PERFILEXAMENCOMPLEMENTARIO(Description) VALUES (#Descripcion)
SELECT IDENT_CURRENT('PERFILEXAMENCOMPLEMENTARIO') AS rowID
END
--Call From PHP replace with your variable and It will return your column rowID with value:
EXEC AltaPerfil 'test'
In the end, all i had to do was adding SET NOCOUNT ON to the SP and it magically worked
ALTER PROCEDURE [dbo].[AltaPerfil](
#Descripcion varchar(50),
#IdPerfil int out
) AS
BEGIN
SET NOCOUNT ON;
INSERT INTO PERFILEXAMENCOMPLEMENTARIO (Descripcion) VALUES (#Descripcion)
SET #IdPerfil = ##IDENTITY
END
I have written a stored procedure in mysql which will create a TEMPORARY TABLE, I want to access the data of TEMPORARY TABLE using Codeigniter.But when I call "$this->db->query()" it returns empty data.
$data=array();
$call_procedure = "CALL sp_Stock()";
$query = $this->db->query($call_procedure);
$sql="SELECT * FROM StockTable";
$query1 = $this->db->query($sql);
I have changed my way to show the data. And I do changes it on stored procedure.
DELIMITER $$
CREATE PROCEDURE sp_Stock()
BEGIN
DECLARE cursor_finish INTEGER DEFAULT 0;
DECLARE m_numofpurchaseBag DECIMAL(10,2)DEFAULT 0;
DECLARE m_purchasedKg DECIMAL(10,2)DEFAULT 0;
DECLARE m_purBagDtlId INTEGER DEFAULT 0;
DECLARE stockCursor CURSOR FOR
SELECT purchase_bag_details.`actual_bags`,
(purchase_bag_details.`net`*purchase_bag_details.`actual_bags`) AS PurchasedKg,
purchase_bag_details.`id` AS PurchaseBagDtlId
FROM
purchase_invoice_detail
INNER JOIN
purchase_bag_details
ON purchase_invoice_detail.`id`= purchase_bag_details.`purchasedtlid`
INNER JOIN
`do_to_transporter`
ON purchase_invoice_detail.`id` = do_to_transporter.`purchase_inv_dtlid`
WHERE purchase_invoice_detail.`teagroup_master_id`=6
AND purchase_invoice_detail.`id`=1481
AND do_to_transporter.`in_Stock`='Y';
-- declare NOT FOUND handler
DECLARE CONTINUE HANDLER
FOR NOT FOUND SET cursor_finish = 1;
DROP TEMPORARY TABLE IF EXISTS StockTable;
#temptable creation
CREATE TEMPORARY TABLE IF NOT EXISTS StockTable
(
purchaseBagDtlId INT,
purchasedBag NUMERIC(10,2),
purchasedKg NUMERIC(10,2),
blendedBag NUMERIC(10,2),
blendedKg NUMERIC(10,2),
stockBag NUMERIC(10,2),
stockKg NUMERIC(10,2)
);
#temptable creation
OPEN stockCursor ;
get_stock : LOOP
FETCH stockCursor INTO m_numofpurchaseBag,m_purchasedKg,m_purBagDtlId;
IF cursor_finish = 1 THEN
LEAVE get_stock;
END IF;
/*SELECT m_numofpurchaseBag,m_purchasedKg,m_purBagDtlId; */
/* Blending bag query*/
SET #m_numberofBlndBag:=0;
SET #m_BlndKg:=0;
/* Blend bag*/
SELECT #m_numberofBlndBag:=SUM(blending_details.`number_of_blended_bag`) AS belendedBag INTO #m_numberofBlndBag
FROM blending_details
WHERE blending_details.`purchasebag_id`= m_purBagDtlId
GROUP BY
blending_details.`purchasebag_id`;
#Blend Bag
#Blend Kgs
SELECT #m_BlndKg:=SUM(blending_details.`qty_of_bag` * blending_details.`number_of_blended_bag`) AS blendkg INTO #m_BlndKg
FROM blending_details
WHERE blending_details.`purchasebag_id`= m_purBagDtlId
GROUP BY
blending_details.`purchasebag_id`;
SET #m_StockBag:=(m_numofpurchaseBag - #m_numberofBlndBag);
SET #m_StockKg:=(m_purchasedKg - #m_BlndKg);
INSERT INTO StockTable
(
purchaseBagDtlId ,
purchasedBag ,
purchasedKg ,
blendedBag ,
blendedKg ,
stockBag ,
stockKg
)VALUES(m_purBagDtlId,m_numofpurchaseBag,m_purchasedKg,#m_numberofBlndBag,#m_BlndKg,#m_StockBag,#m_StockKg);
END LOOP get_stock;
CLOSE stockCursor;
SELECT * FROM StockTable;
#DROP TABLE StockTable;
END$$
DELIMITER ;
#CALL sp_Stock();
Anywhere I am using a temp table I am executing this before the temp table is created:
$this->db->query('DROP TABLE IF EXISTS StockTable');
I seem to remember reading someone having the same problem as you and for some reason you have to execute the above first.
So try:
$data=array();
$call_procedure = "CALL sp_Stock()";
$this->db->query('DROP TABLE IF EXISTS StockTable');
$query = $this->db->query($call_procedure);
$sql="SELECT * FROM StockTable";
$query1 = $this->db->query($sql);
I have the following stored procedure on my MS SQL server:
CREATE PROCEDURE checkFollowing
(
#myMemberID INT,
#otherMemberID INT
)
AS
BEGIN
IF EXISTS (SELECT 1 FROM Followers WHERE follower = #myMemberID AND followed = #otherMemberID)
RETURN 1
ELSE
RETURN 0
END
GO
In my PHP code I have this method so far:
function iAmFollowing($mymemberID, $otherMemberID) {
$query = "EXEC checkFollowing #myMemberID = ?, #otherMemberID = ?";
$stmt = sqlsrv_query($this->con, $query, array(&$mymemberID, &$otherMemberID));
$result = sqlsrv_fetch_array($stmt);
return $result[0];
}
As I have realised now, is that I can't get return values with the sqlsrv_fetch_array() command. But I canøt seem to figure out how to fetch the outpur value using php.
Does someone know how to achieve this?
Any help will be gratly appreciated.
SOLUTION
CREATE PROCEDURE checkFollowing
(
#myMemberID INT,
#otherMemberID INT
)
AS
BEGIN
IF EXISTS (SELECT 1 FROM Followers WHERE follower = #myMemberID AND followed = #otherMemberID)
SELECT 1 AS 'output'
ELSE
SELECT 0 AS 'output'
END
GO
And the php code should be almost the same. Just change the return value to:
$result['output'];
Declare OUTPUT parameter in your SP's parameter list. The OUTPUT parameter return data back to the calling application. check this Link for more info
CREATE PROCEDURE checkFollowing
(
#myMemberID INT,
#otherMemberID INT,
#output INT OUTPUT
)
AS
BEGIN
IF EXISTS (SELECT 1 FROM Followers WHERE follower = #myMemberID AND followed = #otherMemberID)
SELECT #output= 1
ELSE
SELECT #output= 0
END
GO
Update:
To Call the SP and to store the Output. Try something like this
DECLARE #appout int; -- variable to hold the data returned by SP.
EXEC checkFollowing 10,20, #output = #appout OUTPUT; -- This is how i will call a SP.
#appout - will hold the data returned by the procedure.
I am trying to run a procedure in which i will send the table name to fetch all records from it..so that i don't have to create different procedure...but i am facing some problem in that.
ALTER PROCEDURE [dbo].[getTableData]
-- Add the parameters for the stored procedure here
#tableName Varchar(100),
#whrFldName NVarchar(100)
AS
BEGIN
-- SET NOCOUNT ON added to prevent extra result sets from
-- interfering with SELECT statements.
SET NOCOUNT ON;
-- Insert statements for procedure here
DECLARE #ActualTableName AS NVarchar(255)
SELECT #ActualTableName = QUOTENAME( TABLE_NAME )
FROM INFORMATION_SCHEMA.TABLES
WHERE TABLE_NAME = #tableName
DECLARE #sql AS NVARCHAR(MAX)
SELECT #sql = 'SELECT * FROM ' + #ActualTableName + ' WHERE ' +
#whrFldName + ' = ''y'' ;'
--PRINT #sql
EXEC(#SQL)
END
The PHP code is this..
$sql ="EXEC [dbo].[getTableData] 'tbl_services','serviceStatus'";
$rst = odbc_exec($connection, $sql);
$i = 0;
while($result = odbc_fetch_array($rst))
{
$returnPageData[$i] = $result;
$i++;
}
It executes just fine in server but when I call it from my PHP code, it returns null.
Here if I remove * and place fields it works fine..I have tested my code well,it specially creates the problem for a Text type field..
If i change the procedure to this,it works fine..
ALTER PROCEDURE [dbo].[getTableData]
-- Add the parameters for the stored procedure here
#rowsPerPage as bigint,
#pageNum as bigint
AS
BEGIN
-- SET NOCOUNT ON added to prevent extra result sets from
-- interfering with SELECT statements.
SET NOCOUNT ON;
WITH SQLPaging AS (
SELECT TOP(#rowsPerPage * #pageNum) ROW_NUMBER() OVER (ORDER BY creationDate DESC)
AS resultNum, *
FROM [DB_SB].[dbo].[tbl_blog] )
SELECT
blogTitle,
blogSlug,
blogImage,
substring( blogContent, 1, 210 ) AS blogContent,
creationDate,
blogAddedBy
FROM SQLPaging WITH (nolock) WHERE resultNum > ((#pageNum - 1) * #rowsPerPage)
END
But this is no logical..if i send fields everytime..this is not what i want exactly..
Any solution??please help...
You need to use SQL Server Profiler to see what’s actually getting to database engine.
If your stored procedure is executed correctly when run from SSMS then there is a problem somewhere in PHP part.
Are you using the same database using when testing from SSMS? There might be some issue in that…
I have a procedure called SELECT_DESCRIPTION that receives an id and returns a Description field I need to show in my page.
Now I want to create a new procedure that having a number of ids coming from a select clause like this:
SELECT id FROM MYTABLE
Can pass it to the SELECT_DESCRIPTION procedure so I can have the same number of descriptions
If I was using php I would be doing something like this:
$sql=”SELECT id FROM MYTABLE”;
$result = mysql_query($sql) //using mysql to make the example faster but TSQL is what I use
or die(mysql_error());
while($row = mysql_fetch_array( $result )) {
$newSql = "EXEC SELECT_DESCRIPTION #id = '$row[‘id’]'";
//do whatever with $newSql
}
But I need to use a procedure. Is is possible to do it? How can I do it?
Thanks a ton!
So you're wanting to do all of this in TSQL? Something like this would do it:
DECLARE #tmp TABLE (tmpID INT IDENTITY, tblID INT)
DECLARE #RecordCount INT,
#LoopCount INT,
#ID INT
INSERT INTO #tmp SELECT id FROM MYTABLE
SELECT #RecordCount = COUNT(*) FROM #tmp
SET #LoopCount = 1
WHILE #LoopCount <= #RecordCount
BEGIN
SELECT #ID = tblID FROM #tmp WHERE tmpID = #LoopCount
EXEC SELECT_DESCRIPTION #ID
SELECT #LoopCount = #LoopCount + 1
END
The #tmp table has an identity column that insures whatever data you're running the loop on has consecutive row numbers (1, 2, 3, 4, etc).