How to pass an array to SQL Server using PHP - 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

Related

Getting output parameter value from Microsoft SQL stored procedure using Laravel

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;

Call stored procedures in a loop using PDO gives previous calls results

I am in a need to call a stored procedure in a loop by using PDO. This procedure return multiple rows (not by OUT param). The problem I am facing is that sequential call adds all the results from previous calls to the new result. Say, if a single call with specific param returns 20 rows, second call will return 40 rows, third one - 60, etc. Param can be different from call to call while the results will still stack. The code I am using:
public function call($proc, $params) {
$this->query = 'CALL '.$proc.'(?);';
$this->statement = $this->pdo->prepare($this->query);
$this->statement->execute($params);
$data = $this->statement->fetchAll(PDO::FETCH_ASSOC);
$this->statement->nextRowset();
$this->statement->closeCursor();
return $data;
}
From my understanding, I have probably failed with freeing the resources and fetching entire data, however no data is available after fetchAll. Why am I getting results from previous calls?
Edit: here is a similar code of sproc used in application (_type is IN param):
BEGIN
DECLARE _start_entry INT UNSIGNED;
DECLARE _next_entry INT UNSIGNED;
CREATE TEMPORARY TABLE IF NOT EXISTS `tableT` AS (SELECT * FROM `table` LIMIT 0);
SELECT `entry` FROM `table` WHERE `type` = _type LIMIT 1 INTO _start_entry;
read_loop: LOOP
INSERT INTO `tableT` (SELECT * FROM `table` WHERE entry = _start_entry);
SELECT `next_entry` FROM `table` WHERE entry = _start_entry INTO _next_entry;
SELECT _next_entry INTO _start_entry;
IF _next_entry = 0 THEN
LEAVE read_loop;
END IF;
END LOOP read_loop;
SELECT * FROM `tableT`;
END
Turns out the problem was that multiple calls were perfomed within the same session. This leads temporary table tableT to exist among all the calls and contain results from previous calls. Easy fix:
[...]
SELECT * FROM `tableT`;
DROP TABLE `tableT`; <-- this
END

Creating stored procedure for multiple insert and alter table queries

$link->query("DROP TABLE IF EXISTS table2");
$link->query("CREATE TABLE table2 (newcol BIGINT UNSIGNED PRIMARY KEY)");
$result=$link->query("select col1 from table1");
while($data=$result->fetch_array(MYSQL_ASSOC))
{
$link->query("insert into table2 (newcol) values($data['col1']);
$link->query(""ALTER TABLE table2 ADD `".$data['col1']."` BIGINT DEFAULT 0"");
}
What Iam trying to do is
Create a table "table2" with one column "newcol".
select all the values of "col1" from "table1" And
for each value of col1 from table1
-insert the value into "newcol" of table2 And
-add a column named (value from col1 of table 1) into "table2"
The above code looks very neat and efficient in php , but the problem is it takes some amount of time .So I think its better to convert these into MySQL Stored procedure .Since I'm new to stored procedures , very much confused .Please help me guys.
Of course, I couldn't test it, but it is compiling fine on on my computer.
DELIMITER //
CREATE PROCEDURE `myProcedure` ()
BEGIN
DECLARE _done BOOLEAN DEFAULT FALSE;
DECLARE _myField BIGINT UNSIGNED DEFAULT 0;
/* the cursor here is like your PDOStatement
* it is used to fetch data */
DEClARE _myReader CURSOR FOR
SELECT `col1` FROM `table1`;
/* it is not very elegant, but we need to throw an exception
* to break the loop */
DECLARE CONTINUE HANDLER
FOR NOT FOUND SET _done = TRUE;
DROP TABLE IF EXISTS `table2`;
CREATE TABLE `table2` (
`newcol` BIGINT UNSIGNED PRIMARY KEY
);
/* you open your PDOStatement */
OPEN _myReader;
/* myLoop is like a GOTO*/
myLoop: LOOP
/* $result->fetch_array(MYSQL_ASSOC)*/
FETCH _myReader INTO _myField;
/* if the no data exception had been thrown,
* goto the end of the loop */
IF _done = 1 THEN
LEAVE myLoop;
END IF;
INSERT INTO `table2` (newcol) VALUES (_myField);
ALTER TABLE `table2` ADD `_myField` BIGINT DEFAULT 0;
END LOOP myLoop;
/* close your PDO object */
CLOSE _myReader;
END //
Jonathan Parent Lévesque helped me a lot in figuring out how the looping inside stored procedures work and to get the overall structure for the stored procedure equivalent to the php code described in the question above.
Thanks Jonathan Parent Lévesque
But in his code Adding column name using a variable didn't work as expected.
Finally I figured it out
BEGIN
DECLARE _done BOOLEAN DEFAULT FALSE;
DECLARE _myField BIGINT DEFAULT 0;
DEClARE _myReader CURSOR FOR
SELECT id FROM `tags`;
DECLARE CONTINUE HANDLER
FOR NOT FOUND SET _done = TRUE;
DROP TABLE IF EXISTS `tag_similarity`;
CREATE TABLE `tag_similarity` (
`tag` BIGINT UNSIGNED PRIMARY KEY
);
OPEN _myReader;
myLoop: LOOP
FETCH _myReader INTO _myField;
IF _done = 1 THEN
LEAVE myLoop;
END IF;
INSERT INTO `tag_similarity` (tag) VALUES (_myField);
SET #sql = CONCAT('ALTER TABLE tag_similarity ADD `',_myfield,'` BIGINT DEFAULT 0');
PREPARE stmt FROM #sql;
EXECUTE stmt ;
DEALLOCATE PREPARE stmt;
END LOOP myLoop;
CLOSE _myReader;
END

Get Updated Value in MySQL instead of affected rows

I've been trying to find an answer to this question, but haven't found any definitive "yes" or "no" in all my research.
I'm running a simple MySQL query like this:
UPDATE item SET `score`=`score`+1 WHERE `id`=1
Is there a way for that query to return the updated value, instead of the number of rows affected? Just as a reference, I'm doing this in PHP, so the actual code looks like:
$sql = "UPDATE item SET `score`=`score`+1 WHERE `id`=1";
$new_value = mysql_query($sql);
//Unfortunately this does not return the new value
I know I could do a second query and just SELECT the value, but I'm trying to cut down on queries as much as possible. Is there a way?
You can do it with a stored procedure that updates, and then selects the new value into an output parameter.
The following returns one column new_score with the new value.
DELIMITER $$ -- Change DELIMITER in order to use ; withn the procedure
CREATE PROCEDURE increment_score
(
IN id_in INT
)
BEGIN
UPDATE item SET score = score + 1 WHERE id = id_in;
SELECT score AS new_score FROM item WHERE id = id_in;
END
$$ -- Finish CREATE PROCEDURE statement
DELIMITER ; -- Reset DELIMITER to standard ;
In PHP:
$result = mysql_query("CALL increment_score($id)");
$row = mysql_fetch_array($result);
echo $row['new_score'];
No, there's nothing like postgresql's UPDATE ... RETURNING output_expression in MySQL (yet?).
If you don't want to run another Query SELECT then here is another way to do it. I have modified Mr. Berkowski code for reference:
DELIMITER $$
CREATE PROCEDURE increment_score
(
IN id_in INT
)
BEGIN
set #newScore := null;
UPDATE item SET score = IF((#newScore := score+1) <> NULL IS NULL, #newScore, NULL) WHERE id = id_in;
SELECT #newScore;
END
DELIMITER ;
No you cant. You could make a function or stored procedure that could do the insert and return the updated value but that would still require you to execute two queries from within the function or stored procedure.
You can create a trigger, and you will know everything about the modifications.

How to create and call MySQL stores procedures?

The table[file_request ] structure:
user_id[INT] file_id[CHAR(10)] all_files
This is the SQL code which work fine in MySQL clien: I am using heidisql
DROP PROCEDURE IF EXISTS check_user_files;
DELIMITER \\
CREATE PROCEDURE check_user_files(IN p_user_id INT,IN p_file_id CHAR(10),IN p_all_files VARCHAR(500))
BEGIN
IF EXISTS(SELECT 1 FROM file_request WHERE user_id = p_user_id AND movie_id = p_file_id) THEN
UPDATE file_request SET `requring_date`=NOW(),`all_files`= p_all_files WHERE `user_id`=p_user_id AND `movie_id`=p_file_id;
ELSE
INSERT INTO file_request (`user_id`,`requring_date`,`movie_id`,`all_files`)
VALUES (p_user_id,NOW(),p_file_id,p_all_files);
END IF;
END \\
DELIMITER ;
CALL check_user_files('23','T40431284','07 08 10 11 13 14');
DELIMITER ;
CALL check_user_files('23','F87951','01 02 03');
And I trying to create and execute the SQL query from PHP [didn't work] :
// create the call procedure statements
foreach($fileData as $key=>$value){
$callSP .= "DELIMITER ; \n
CALL check_user_files('$userID','$key','$value');\n";
}
$insert_file_request_query = "DROP PROCEDURE IF EXISTS check_user_files;
DELIMITER \\\\
CREATE PROCEDURE check_user_files(IN p_user_id INT,IN p_file_id CHAR(10),IN p_all_files VARCHAR(500))
BEGIN
IF EXISTS(SELECT 1 FROM file_request WHERE user_id = p_user_id AND movie_id = p_file_id) THEN
UPDATE file_request SET `requring_date`=NOW(),`all_files`= p_all_files WHERE `user_id`=p_user_id AND `movie_id`=p_file_id;
ELSE
INSERT INTO file_request (`user_id`,`requring_date`,`movie_id`,`all_files`)
VALUES (p_user_id,NOW(),p_file_id,p_all_files);
END IF;
END \\\\
$callSP";
mysqli_query($conn,$insert_file_request_query);
The SQL query which created from PHP didn't work as in the MySQL client!?
So, how can I fix it!?
[update1]
I found that the SQL query must in the special format [ the formate which work fine in the MySQL client] or shouldn't work,I tried to copy and paste the query which echo from the PHP, the query code become one line and couldn't execute in MySQL client,too.
[update2]
The code of create store procedure will work fine when I execute it alone from PHP.I mean,I split the whole process into three parts and execute them one by one.
part1: drop the procedure if it was exists; [using mysqli_query()]
part2: create the procedure;[using mysqli_query()]
part3:call the procedure;[using mysqli_multi_query()]
$insert_file_request_query = '';
foreach($fileData as $key=>$value){
$insert_file_request_query .= "CALL check_save_file_request('$userID','$key','$value');";
}
mysqli_multi_query($conn,$insert_file_request_query);
And my final solution was to create the Store Procedure in MySQL and call it from the PHP.It works fine now.
Thank you very much!!
You can't combine multiple statements in mysqli_query. Split out the definition of the stored procedure from the CALLs to it. If that still fails, we'll need the full and exact error message that you receive.

Categories