Getting output parameter value from Microsoft SQL stored procedure using Laravel - php

I am trying to insert a record into the Microsoft SQL database via store procedure using Laravel and get the value from an output parameter. My record is inserted but did not get #RetValue.
For this, I tried
DB::select("DECLARE #RetValue INT; SELECT #RetValue as 'return'; EXEC AddDistrict 'somevalue', 1, #RetValue OUTPUT; SELECT #RetValue as 'abc';");
DB::select(DB::Raw("Declare #RetValue int EXEC AddDistrict 'somevalue', '1', #RetValue OUTPUT"),'select #RetValue as abc');
DB::select(DB::statement('CALL AddDistrict("DName"="asdfasdf", "PID"=1,"RetValue"="" )').'#RetValue as RetValue');
DB::select(" EXEC AddDistrict ?, ?", array( 'some_value',1));
DB::select(DB::raw("exec AddDistrict #DName = 'some_value', #PID = 1, #RetValue=''"));
DB::select('CALL AddDistrict(?, ?, ?)',
array(
'DName' => $request->DistrictName,
'PID' => $request->province,
'RetValue' => ''
));
DB::select('exec AddDistrict(?,?)',"some_value',1);
and many others but did not get the #RetValue. mostly I get an empty array like this [].
My Store Procedure looks like
CREATE PROCEDURE [dbo].[AddDistrict]
#DName nvarchar(50)
,#PID int
,#RetValue int output
AS
BEGIN
-- SET NOCOUNT ON added to prevent extra result sets from
-- interfering with SELECT statements.
SET NOCOUNT ON;
-- Insert statements for procedure here
if not exists(select * from District where District_Name = #DName)
begin
INSERT INTO [dbo].District
([District_Name],ProvienceID)
VALUES (#DName,#PID)
set #RetValue=1;
end
else
begin
set #RetValue=-1;
end
END
I want if the record inserts then give me 1 if did not insert then give me -1 as described in the SP

I found a solution to that. Maybe it's not the proper way. But my code is now running smoothly after the below changes.
Just remove this variable #RetValue int output and replace set #RetValue=1; to SELECT 1;

Related

Can I call a stored procedure on each iteration of an array? PHP

I want to loop through an associative array that represents a table's columns and values, and call a stored procedure on each iteration that will insert each value into its respective column. The assoc. array and loop looks like this:
public static function update(
int $auctionId,
string $title,
string $description
) : void
{
$new = [
'auction_title' => $title,
'description' => $description
];
foreach ($new as $columnName => $value) {
Database::conn()->callSP('sp_auctions_update', [$auctionId, $columnName, $value]);
}
}
The stored procedure looks like this:
DELIMITER $$
DROP PROCEDURE IF EXISTS sp_auctions_update $$
CREATE PROCEDURE sp_auctions_update(
IN auctionId INT UNSIGNED,
IN columnName,
IN value,
)
SQL SECURITY INVOKER
MODIFIES SQL DATA
BEGIN
UPDATE auctions SET #columnName=#value, WHERE id=#auctionId;
END $$
DELIMITER ;
Is this possible to do? Or is there a better alternative? Many thanks
do you know what the prepared statement would look like in this instance?
CREATE PROCEDURE sp_auctions_update(
IN auctionId INT UNSIGNED,
IN columnName VARCHAR(64),
IN `value` INT UNSIGNED
)
SQL SECURITY INVOKER
MODIFIES SQL DATA
BEGIN
-- Build SQL query text, insert column name from variable into it
SET #sql := CONCAT('UPDATE auctions SET ', columnName, '=? WHERE id=?;');
-- Reassign parameters values from local variables to user-defined ones
-- because local variables cannot be used in USING
SET #value := `value`;
SET #auctionId := auctionId;
-- Prepare and execute the query
PREPARE stmt FROM #sql;
EXECUTE stmt USING #value, #auctionId;
DEALLOCATE PREPARE stmt;
END
Alternatively you may concat ALL parameters values into the query text:
CREATE PROCEDURE sp_auctions_update(
IN auctionId INT UNSIGNED,
IN columnName VARCHAR(64),
IN `value` INT UNSIGNED
)
SQL SECURITY INVOKER
MODIFIES SQL DATA
BEGIN
-- Build SQL query text, insert parameters from variables into it
SET #sql := CONCAT('UPDATE auctions SET ', columnName, '=\'', `value`, '\' WHERE id=', auctionId, ';');
-- Prepare and execute the query
PREPARE stmt FROM #sql;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;
END
Caution.
The columnName parameter value is inserted into SQL query text as-is - so injection is possible. You must add the code which controls this parameter value. For example you may check that the column with provided name exists in table structure.
Another 2 parameters cannot be a source of injection due to their numeric datatype.

Syntax error in SELECT query inside PHP script

I am trying to create a query inside a PDO script that checks if a record exists if it does the query should update the record and if it doesn't exist it should create a new one.
The column that should only exist once in the table is not an INDEX key (cannot make it unique right now) so it is not set as unique and I cannot use the ON DUPLICATE KEY UPDATE
I would like to use this queries logic below to make it work:
$stmt = $conn->prepare('IF EXISTS (SELECT * FROM `Table1` WHERE `code`= :code )
UPDATE `Table1`
SET `code_stat` = 2
WHERE code = :code
ELSE
INSERT INTO `Table1` (`code`,`code_stat`)
VALUES (:code, 2 ) ' );
$stmt->execute([
'code' => $_POST['code']
]);
The problem is when executing the query I get the following error saying there is a syntax problem:
SQL syntax; check the manual that corresponds
to your MySQL server version for the right syntax to use near
'IF EXISTS (SELECT * FROM Table1 WHERE code= ? ) UPDATE Table1' at line 1
If you can't add a unique key to the table, you can attempt an update first, and if that doesn't update any rows, do an insert. Something like this:
$stmt = $conn->prepare('UPDATE `Table1` SET `code_stat` = 2 WHERE code = :code');
$stmt->execute(array(':code' => $_POST['code']));
if (!$stmt->rowCount()) {
// no rows updated, so insert
$stmt = $conn->prepare('INSERT INTO `Table1` (`code_stat`, `code`) VALUES (2, :code)');
$stmt->execute(array(':code' => $_POST['code']));
}
Note that you may need to set the PDO::MYSQL_ATTR_FOUND_ROWS attribute to ensure that the UPDATE query returns 1 if it finds the row but the value doesn't change. You must set that attribute when you make the connection e.g.
$conn = new PDO($dsn, $user, $pass, array(PDO::MYSQL_ATTR_FOUND_ROWS => true));
Why not write a stored procedure to handle this, similar to the below:
DROP PROCEDURE IF EXISTS db.SP_NEW_CODE;
CREATE PROCEDURE db.`SP_NEW_CODE`(IN `in_code` INT)
BEGIN
DECLARE numFound INT DEFAULT 0;
SET numFound=(SELECT * FROM `Table1` WHERE `code`= in_code);
IF (numFound=0) THEN
INSERT INTO `Table1` (`code`,`code_stat`) VALUES (in_code, 2 );
ELSE
UPDATE `Table1` SET `code_stat` = 2 WHERE code = in_code
END IF;
END;
From your code, simple execute CALL SP_NEWCODE(3); (for example, where 3 is the appropriate code value).

How to pass an array to SQL Server using PHP

Good day,
If I have the following code in SQL Server:
CREATE TYPE PartList
AS TABLE
(
PartID varchar(30),
Quantity int
);
GO
CREATE PROC spInsertPartList
#List AS PartList READONLY
AS
BEGIN
SET NOCOUNT ON;
INSERT INTO Part (PartID, Quantity)
VALUES (SELECT PartID, Quantity FROM #List)
END
GO
Can I now call this procedure from PHP stating something like the following:
$array = array('PartNr123' => 50, 'PartNr25' => 4);
$stmt = mssql_init('spInsertPartList');
mssql_bind($stmt,'#List', &$array, PartList, false, false);
mssql_execute($stmt);
I found the code for the SQL statements here, but unfortunately the code example works with C# DataTable.
EDIT:
Furthermore I am getting the following errors when executing the SQL script:
Msg 2715, Level 16, State 3, Procedure InsertStockTake, Line 194
Column, parameter, or variable #1: Cannot find data type dbo.CallPartList
And also this:
Msg 1087, Level 16, State 1, Procedure InsertStockTake, Line 200
Must declare the table variable "#partList".
Which is caused by the following code:
CREATE PROC dbo.InsertStockTake
#partList AS dbo.CallPartList READONLY
AS
BEGIN
BEGIN TRY
BEGIN TRANSACTION
DECLARE #partNr varchar(15), #qtyCount smallint, #qtyDB smallint
DECLARE curStock CURSOR FOR (SELECT PartNr, Qty FROM #partList)
OPEN curStock
FETCH NEXT FROM curCallPart INTO #partNr, #qtyCount
WHILE ##FETCH_STATUS = 0
BEGIN
SELECT #qtyDB = StockOH FROM dbo.Stock WHERE PartNr =
#partNr
INSERT INTO scArchive.StockLevel(PartNr,
StockOHDatabase, StockOHCounted, DateCaptured)
VALUES (#partNr, #qtyDB, #qtyCount, GETDATE())
FETCH NEXT FROM curCallPart INTO #partNr, #qtyCount
END
CLOSE curStock
DEALLOCATE curStock
COMMIT
END TRY
BEGIN CATCH
THROW;
ROLLBACK
END CATCH
END
GO
Thank you in advance
No needed for this question any more. I used mysqli_* in php and adjusted my table structure and moved to MySQL rather than MS SQL

Read OUTPUT values from SQL stored procedure using PDO and SQLSRV

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

MSSQL dose not return data for all fields

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…

Categories