Executing a stored procedure with cursor in PHP - php

I have a stored procedure that I am trying to call from my php. Here is the stored procedure:
BEGIN
DECLARE done INT DEFAULT FALSE;
declare phone_temp VARCHAR(20) default '';
declare phone_cur cursor for SELECT DISTINCT sentNum FROM Queue;
declare continue handler for not found set done = true;
#create temp table
create temporary table if not exists temp_return AS SELECT * FROM Queue LIMIT 0;
#empty if exists
delete from temp_return;
open phone_cur;
phone_loop: LOOP
fetch phone_cur into phone_temp;
if done then
leave phone_loop;
end if;
insert into temp_return SELECT * FROM Queue WHERE num2=phone_temp LIMIT 2;
insert into temp_return SELECT * FROM Queue WHERE num1=phone_temp LIMIT 1;
end loop phone_loop;
close phone_cur;
select * from temp_return;
drop table if exists temp_return;
END
Directly in mysql workbench, calling it works. In php, it does not work. Here is my php:
function grabFromSmsQueue(){
global $myStmt, $conn;
if(isset($myStmt)){
$myStmt -> execute();
}
else{
$query = "CALL myStoredProc();";
$myStmt = $conn->stmt_init();
$myStmt -> prepare($query);
$myStmt -> execute();
}
$result = $myStmt -> get_result();
//print_r ($result);
$info = [];
if(isset($result)){
while($data = $result->fetch_assoc()){
$info[] = $data;
}
}
return $info;
}
Connecting like this, I get the following error
The localhost page isn’t working
localhost didn’t send any data.
ERR_EMPTY_RESPONSE
I traced my problem back to an issue with $data = $result->fetch_assoc(), because when I comment that out and put in the print_r I get something actually returned, which is mysqli_result Object ( [current_field] => 0 [field_count] => 9 [lengths] => [num_rows] => 0 [type] => 1 ). I have drawn the conclusion that it is not working because [num_rows] => 0.
Now, going back to my stored procedure, I took out all mentions of a cursor and replaced it with a hard-coded value, and it worked in both workbench and php. I have already verified that the user connecting through php has permission, that the connection is open, and that the same code can execute other stored procedures (ones that do not include cursors). Does this mean that I can not use cursors in stored procedures that are being called by php? Are there alternatives to cursors? Am I missing something in my php syntax to deal with cursors?

Based on discussions in chat for 3 groupings, and this provided SQLFiddle for test data (not much data there).
Due to testing data with a sliding window of where now() is in relation to that data, the following variable was used to "freeze" now(). Simply to facilitate testing and verification of output.
So, ditch that ultimately and change the 4 references in the code that use it (note that Group 3 uses it twice).
The now() variable:
select #theNow:=now();
-- REM OUT the following line. It is used only for testing (as now will chg, your data won't)
select #theNow:='2016-06-23 14:00:00';
The Query:
select id,sentNum,message,sentTime,startAtTime,sentByTime,msgType,theGrp from
( select id,sentNum,message,sentTime,startAtTime,sentByTime,msgType,theGrp,
if(sentNum!=#lastSentNum,greatest(#sentNumChg:=1,0),least(#sentNumChg:=0,1)) as dummy1,
if(theGrp!=#lastGrp,greatest(#grpChg:=1,0),least(#grpChg:=0,1)) as dummy2,
if(#sentNumChg=1 or #grpChg=1,#seqNum:=1,#seqNum:=#seqNum+1) as seqNum,
#lastSentNum:=sentNum as setLast01,
#lastGrp:=theGrp as setLast02
from
( -- GROUP 1: sentByTime<=now(), INVITE
select `id`, `sentNum`, `message`, `sentTime`, `startAtTime`, `sentByTime`, `msgType`, 1 as theGrp
from SmsQueue
where sentByTime<=#theNow and msgType='invite'
UNION ALL
-- GROUP 2 startAtTime<=now(), BROADCAST
select `id`, `sentNum`, `message`, `sentTime`, `startAtTime`, `sentByTime`, `msgType`, 2 as theGrp
from SmsQueue
where startAtTime<=#theNow and msgType='broadcast'
UNION ALL
-- GROUP 3: sentByTime>now() && startAtTime<=now(), INVITE
select `id`, `sentNum`, `message`, `sentTime`, `startAtTime`, `sentByTime`, `msgType`, 3 as theGrp
from SmsQueue
where sentByTime>#theNow and startAtTime<=#theNow and msgType='invite'
) d1
cross join (select #sentNumChg:=0,#grpChg:=0,#lastSentNum:='',#lastGrp:=0,#seqNum:=0) as xParams
order by sentNum,theGrp,sentByTime,id -- id is the tie-break
) d2
where (theGrp=1 and seqNum<3) or (theGrp=2 and seqNum=1) or (theGrp=3 and seqNum=1)
order by sentNum,theGrp;
Output (my client tool is text challenged at the moment):
See my general comments at the top of this answer of mine for advanced variable usage.

Related

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

Sync Framework Insert Triggers With Yii2 not working

I have used Sql Server with PHP framework to Sync online database with local database. I made an application in .net Framework and used Microsoft SyncFramework to sync two databases. The problem I am facing now is that whenever database is provisioned and tracking tables are made along with triggers and stored procedures. All create functionality stops working in the PHP app. I have used the following condition in YII to save a few more thing in YII framework application.
if ($loaded && $model->save()) {
}
$model->save() always returns false and do not return any error. On the other hand when I try to insert record in the database using .Net entity framework it returns true. So my Guess at this time is that there is some thing that has a conflict with $model->save() of YII and sql insert trigger made by Sync Framework.
Any pointers to solve this problem will be appreciated.
Note The problem only occurs with insert trigger. Update and delete trigger works fine. Secondly even in insert trigger, records are inserted in Database
Stored Procedure
/****** Object: StoredProcedure [dbo].[branch_bulkinsert] Script Date: 08/19/2017 3:56:13 PM ******/
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
CREATE PROCEDURE [dbo].[branch_bulkinsert]
#sync_min_timestamp BigInt,
#sync_scope_local_id Int,
#changeTable [branch_BulkType] READONLY
AS
BEGIN
-- use a temp table to store the list of PKs that successfully got updated/inserted
DECLARE #changed TABLE ([ID] varchar(64), PRIMARY KEY ([ID]));
-- update/insert into the base table
MERGE [branch] AS base USING
-- join done here against the side table to get the local timestamp for concurrency check
(SELECT p.*, t.local_update_peer_timestamp FROM #changeTable p LEFT JOIN [branch_tracking] t ON p.[ID] = t.[ID]) AS changes ON changes.[ID] = base.[ID]
WHEN NOT MATCHED BY TARGET AND changes.local_update_peer_timestamp <= #sync_min_timestamp OR changes.local_update_peer_timestamp IS NULL THEN
INSERT ([ID], [sr], [branch_code], [branch_name], [created_by], [address], [is_deleted], [approved], [created_on], [application_ID]) VALUES (changes.[ID], changes.[sr], changes.[branch_code], changes.[branch_name], changes.[created_by], changes.[address], changes.[is_deleted], changes.[approved], changes.[created_on], changes.[application_ID])
OUTPUT INSERTED.[ID] INTO #changed; -- populates the temp table with successful PKs
UPDATE side SET
update_scope_local_id = #sync_scope_local_id,
scope_update_peer_key = changes.sync_update_peer_key,
scope_update_peer_timestamp = changes.sync_update_peer_timestamp,
local_update_peer_key = 0,
create_scope_local_id = #sync_scope_local_id,
scope_create_peer_key = changes.sync_create_peer_key,
scope_create_peer_timestamp = changes.sync_create_peer_timestamp,
local_create_peer_key = 0
FROM
[branch_tracking] side JOIN
(SELECT p.[ID], p.sync_update_peer_timestamp, p.sync_update_peer_key, p.sync_create_peer_key, p.sync_create_peer_timestamp FROM #changed t JOIN #changeTable p ON p.[ID] = t.[ID]) AS changes ON changes.[ID] = side.[ID]
SELECT [ID] FROM #changeTable t WHERE NOT EXISTS (SELECT [ID] from #changed i WHERE t.[ID] = i.[ID])
END
GO
Insert Trigger
/****** Object: Trigger [dbo].[branch_insert_trigger] Script Date: 08/19/2017 3:52:43 PM ******/
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
ALTER TRIGGER [dbo].[branch_insert_trigger] ON [dbo].[branch] FOR INSERT AS
UPDATE [side] SET [sync_row_is_tombstone] = 0, [local_update_peer_key] = 0, [restore_timestamp] = NULL, [update_scope_local_id] = NULL, [last_change_datetime] = GETDATE() FROM [branch_tracking] [side] JOIN INSERTED AS [i] ON [side].[ID] = [i].[ID]
INSERT INTO [branch_tracking] ([i].[ID], [create_scope_local_id], [local_create_peer_key], [local_create_peer_timestamp], [update_scope_local_id], [local_update_peer_key], [sync_row_is_tombstone], [last_change_datetime], [restore_timestamp]) SELECT [i].[ID], NULL, 0, ##DBTS+1, NULL, 0, 0, GETDATE() , NULL FROM INSERTED AS [i] LEFT JOIN [branch_tracking] [side] ON [side].[ID] = [i].[ID] WHERE [side].[ID] IS NULL

pdo update multiple rows in one query [duplicate]

I know that you can insert multiple rows at once, is there a way to update multiple rows at once (as in, in one query) in MySQL?
Edit:
For example I have the following
Name id Col1 Col2
Row1 1 6 1
Row2 2 2 3
Row3 3 9 5
Row4 4 16 8
I want to combine all the following Updates into one query
UPDATE table SET Col1 = 1 WHERE id = 1;
UPDATE table SET Col1 = 2 WHERE id = 2;
UPDATE table SET Col2 = 3 WHERE id = 3;
UPDATE table SET Col1 = 10 WHERE id = 4;
UPDATE table SET Col2 = 12 WHERE id = 4;
Yes, that's possible - you can use INSERT ... ON DUPLICATE KEY UPDATE.
Using your example:
INSERT INTO table (id,Col1,Col2) VALUES (1,1,1),(2,2,3),(3,9,3),(4,10,12)
ON DUPLICATE KEY UPDATE Col1=VALUES(Col1),Col2=VALUES(Col2);
Since you have dynamic values, you need to use an IF or CASE for the columns to be updated. It gets kinda ugly, but it should work.
Using your example, you could do it like:
UPDATE table SET Col1 = CASE id
WHEN 1 THEN 1
WHEN 2 THEN 2
WHEN 4 THEN 10
ELSE Col1
END,
Col2 = CASE id
WHEN 3 THEN 3
WHEN 4 THEN 12
ELSE Col2
END
WHERE id IN (1, 2, 3, 4);
The question is old, yet I'd like to extend the topic with another answer.
My point is, the easiest way to achieve it is just to wrap multiple queries with a transaction. The accepted answer INSERT ... ON DUPLICATE KEY UPDATE is a nice hack, but one should be aware of its drawbacks and limitations:
As being said, if you happen to launch the query with rows whose primary keys don't exist in the table, the query inserts new "half-baked" records. Probably it's not what you want
If you have a table with a not null field without default value and don't want to touch this field in the query, you'll get "Field 'fieldname' doesn't have a default value" MySQL warning even if you don't insert a single row at all. It will get you into trouble, if you decide to be strict and turn mysql warnings into runtime exceptions in your app.
I made some performance tests for three of suggested variants, including the INSERT ... ON DUPLICATE KEY UPDATE variant, a variant with "case / when / then" clause and a naive approach with transaction. You may get the python code and results here. The overall conclusion is that the variant with case statement turns out to be twice as fast as two other variants, but it's quite hard to write correct and injection-safe code for it, so I personally stick to the simplest approach: using transactions.
Edit: Findings of Dakusan prove that my performance estimations are not quite valid. Please see this answer for another, more elaborate research.
Not sure why another useful option is not yet mentioned:
UPDATE my_table m
JOIN (
SELECT 1 as id, 10 as _col1, 20 as _col2
UNION ALL
SELECT 2, 5, 10
UNION ALL
SELECT 3, 15, 30
) vals ON m.id = vals.id
SET col1 = _col1, col2 = _col2;
All of the following applies to InnoDB.
I feel knowing the speeds of the 3 different methods is important.
There are 3 methods:
INSERT: INSERT with ON DUPLICATE KEY UPDATE
TRANSACTION: Where you do an update for each record within a transaction
CASE: In which you a case/when for each different record within an UPDATE
I just tested this, and the INSERT method was 6.7x faster for me than the TRANSACTION method. I tried on a set of both 3,000 and 30,000 rows.
The TRANSACTION method still has to run each individually query, which takes time, though it batches the results in memory, or something, while executing. The TRANSACTION method is also pretty expensive in both replication and query logs.
Even worse, the CASE method was 41.1x slower than the INSERT method w/ 30,000 records (6.1x slower than TRANSACTION). And 75x slower in MyISAM. INSERT and CASE methods broke even at ~1,000 records. Even at 100 records, the CASE method is BARELY faster.
So in general, I feel the INSERT method is both best and easiest to use. The queries are smaller and easier to read and only take up 1 query of action. This applies to both InnoDB and MyISAM.
Bonus stuff:
The solution for the INSERT non-default-field problem is to temporarily turn off the relevant SQL modes: SET SESSION sql_mode=REPLACE(REPLACE(##SESSION.sql_mode,"STRICT_TRANS_TABLES",""),"STRICT_ALL_TABLES",""). Make sure to save the sql_mode first if you plan on reverting it.
As for other comments I've seen that say the auto_increment goes up using the INSERT method, this does seem to be the case in InnoDB, but not MyISAM.
Code to run the tests is as follows. It also outputs .SQL files to remove php interpreter overhead
<?php
//Variables
$NumRows=30000;
//These 2 functions need to be filled in
function InitSQL()
{
}
function RunSQLQuery($Q)
{
}
//Run the 3 tests
InitSQL();
for($i=0;$i<3;$i++)
RunTest($i, $NumRows);
function RunTest($TestNum, $NumRows)
{
$TheQueries=Array();
$DoQuery=function($Query) use (&$TheQueries)
{
RunSQLQuery($Query);
$TheQueries[]=$Query;
};
$TableName='Test';
$DoQuery('DROP TABLE IF EXISTS '.$TableName);
$DoQuery('CREATE TABLE '.$TableName.' (i1 int NOT NULL AUTO_INCREMENT, i2 int NOT NULL, primary key (i1)) ENGINE=InnoDB');
$DoQuery('INSERT INTO '.$TableName.' (i2) VALUES ('.implode('), (', range(2, $NumRows+1)).')');
if($TestNum==0)
{
$TestName='Transaction';
$Start=microtime(true);
$DoQuery('START TRANSACTION');
for($i=1;$i<=$NumRows;$i++)
$DoQuery('UPDATE '.$TableName.' SET i2='.(($i+5)*1000).' WHERE i1='.$i);
$DoQuery('COMMIT');
}
if($TestNum==1)
{
$TestName='Insert';
$Query=Array();
for($i=1;$i<=$NumRows;$i++)
$Query[]=sprintf("(%d,%d)", $i, (($i+5)*1000));
$Start=microtime(true);
$DoQuery('INSERT INTO '.$TableName.' VALUES '.implode(', ', $Query).' ON DUPLICATE KEY UPDATE i2=VALUES(i2)');
}
if($TestNum==2)
{
$TestName='Case';
$Query=Array();
for($i=1;$i<=$NumRows;$i++)
$Query[]=sprintf('WHEN %d THEN %d', $i, (($i+5)*1000));
$Start=microtime(true);
$DoQuery("UPDATE $TableName SET i2=CASE i1\n".implode("\n", $Query)."\nEND\nWHERE i1 IN (".implode(',', range(1, $NumRows)).')');
}
print "$TestName: ".(microtime(true)-$Start)."<br>\n";
file_put_contents("./$TestName.sql", implode(";\n", $TheQueries).';');
}
UPDATE table1, table2 SET table1.col1='value', table2.col1='value' WHERE table1.col3='567' AND table2.col6='567'
This should work for ya.
There is a reference in the MySQL manual for multiple tables.
Use a temporary table
// Reorder items
function update_items_tempdb(&$items)
{
shuffle($items);
$table_name = uniqid('tmp_test_');
$sql = "CREATE TEMPORARY TABLE `$table_name` ("
." `id` int(10) unsigned NOT NULL AUTO_INCREMENT"
.", `position` int(10) unsigned NOT NULL"
.", PRIMARY KEY (`id`)"
.") ENGINE = MEMORY";
query($sql);
$i = 0;
$sql = '';
foreach ($items as &$item)
{
$item->position = $i++;
$sql .= ($sql ? ', ' : '')."({$item->id}, {$item->position})";
}
if ($sql)
{
query("INSERT INTO `$table_name` (id, position) VALUES $sql");
$sql = "UPDATE `test`, `$table_name` SET `test`.position = `$table_name`.position"
." WHERE `$table_name`.id = `test`.id";
query($sql);
}
query("DROP TABLE `$table_name`");
}
Why does no one mention multiple statements in one query?
In php, you use multi_query method of mysqli instance.
From the php manual
MySQL optionally allows having multiple statements in one statement string. Sending multiple statements at once reduces client-server round trips but requires special handling.
Here is the result comparing to other 3 methods in update 30,000 raw. Code can be found here which is based on answer from #Dakusan
Transaction: 5.5194580554962
Insert: 0.20669293403625
Case: 16.474853992462
Multi: 0.0412278175354
As you can see, multiple statements query is more efficient than the highest answer.
If you get error message like this:
PHP Warning: Error while sending SET_OPTION packet
You may need to increase the max_allowed_packet in mysql config file which in my machine is /etc/mysql/my.cnf and then restart mysqld.
There is a setting you can alter called 'multi statement' that disables MySQL's 'safety mechanism' implemented to prevent (more than one) injection command. Typical to MySQL's 'brilliant' implementation, it also prevents user from doing efficient queries.
Here (http://dev.mysql.com/doc/refman/5.1/en/mysql-set-server-option.html) is some info on the C implementation of the setting.
If you're using PHP, you can use mysqli to do multi statements (I think php has shipped with mysqli for a while now)
$con = new mysqli('localhost','user1','password','my_database');
$query = "Update MyTable SET col1='some value' WHERE id=1 LIMIT 1;";
$query .= "UPDATE MyTable SET col1='other value' WHERE id=2 LIMIT 1;";
//etc
$con->multi_query($query);
$con->close();
Hope that helps.
You can alias the same table to give you the id's you want to insert by (if you are doing a row-by-row update:
UPDATE table1 tab1, table1 tab2 -- alias references the same table
SET
col1 = 1
,col2 = 2
. . .
WHERE
tab1.id = tab2.id;
Additionally, It should seem obvious that you can also update from other tables as well. In this case, the update doubles as a "SELECT" statement, giving you the data from the table you are specifying. You are explicitly stating in your query the update values so, the second table is unaffected.
You may also be interested in using joins on updates, which is possible as well.
Update someTable Set someValue = 4 From someTable s Inner Join anotherTable a on s.id = a.id Where a.id = 4
-- Only updates someValue in someTable who has a foreign key on anotherTable with a value of 4.
Edit: If the values you are updating aren't coming from somewhere else in the database, you'll need to issue multiple update queries.
No-one has yet mentioned what for me would be a much easier way to do this - Use a SQL editor that allows you to execute multiple individual queries. This screenshot is from Sequel Ace, I'd assume that Sequel Pro and probably other editors have similar functionality. (This of course assumes you only need to run this as a one-off thing rather than as an integrated part of your app/site).
And now the easy way
update my_table m, -- let create a temp table with populated values
(select 1 as id, 20 as value union -- this part will be generated
select 2 as id, 30 as value union -- using a backend code
-- for loop
select N as id, X as value
) t
set m.value = t.value where t.id=m.id -- now update by join - quick
Yes ..it is possible using INSERT ON DUPLICATE KEY UPDATE sql statement..
syntax:
INSERT INTO table_name (a,b,c) VALUES (1,2,3),(4,5,6)
ON DUPLICATE KEY UPDATE a=VALUES(a),b=VALUES(b),c=VALUES(c)
use
REPLACE INTO`table` VALUES (`id`,`col1`,`col2`) VALUES
(1,6,1),(2,2,3),(3,9,5),(4,16,8);
Please note:
id has to be a primary unique key
if you use foreign keys to
reference the table, REPLACE deletes then inserts, so this might
cause an error
I took the answer from #newtover and extended it using the new json_table function in MySql 8. This allows you to create a stored procedure to handle the workload rather than building your own SQL text in code:
drop table if exists `test`;
create table `test` (
`Id` int,
`Number` int,
PRIMARY KEY (`Id`)
);
insert into test (Id, Number) values (1, 1), (2, 2);
DROP procedure IF EXISTS `Test`;
DELIMITER $$
CREATE PROCEDURE `Test`(
p_json json
)
BEGIN
update test s
join json_table(p_json, '$[*]' columns(`id` int path '$.id', `number` int path '$.number')) v
on s.Id=v.id set s.Number=v.number;
END$$
DELIMITER ;
call `Test`('[{"id": 1, "number": 10}, {"id": 2, "number": 20}]');
select * from test;
drop table if exists `test`;
It's a few ms slower than pure SQL but I'm happy to take the hit rather than generate the sql text in code. Not sure how performant it is with huge recordsets (the JSON object has a max size of 1Gb) but I use it all the time when updating 10k rows at a time.
The following will update all rows in one table
Update Table Set
Column1 = 'New Value'
The next one will update all rows where the value of Column2 is more than 5
Update Table Set
Column1 = 'New Value'
Where
Column2 > 5
There is all Unkwntech's example of updating more than one table
UPDATE table1, table2 SET
table1.col1 = 'value',
table2.col1 = 'value'
WHERE
table1.col3 = '567'
AND table2.col6='567'
UPDATE tableName SET col1='000' WHERE id='3' OR id='5'
This should achieve what you'r looking for. Just add more id's. I have tested it.
UPDATE `your_table` SET
`something` = IF(`id`="1","new_value1",`something`), `smth2` = IF(`id`="1", "nv1",`smth2`),
`something` = IF(`id`="2","new_value2",`something`), `smth2` = IF(`id`="2", "nv2",`smth2`),
`something` = IF(`id`="4","new_value3",`something`), `smth2` = IF(`id`="4", "nv3",`smth2`),
`something` = IF(`id`="6","new_value4",`something`), `smth2` = IF(`id`="6", "nv4",`smth2`),
`something` = IF(`id`="3","new_value5",`something`), `smth2` = IF(`id`="3", "nv5",`smth2`),
`something` = IF(`id`="5","new_value6",`something`), `smth2` = IF(`id`="5", "nv6",`smth2`)
// You just building it in php like
$q = 'UPDATE `your_table` SET ';
foreach($data as $dat){
$q .= '
`something` = IF(`id`="'.$dat->id.'","'.$dat->value.'",`something`),
`smth2` = IF(`id`="'.$dat->id.'", "'.$dat->value2.'",`smth2`),';
}
$q = substr($q,0,-1);
So you can update hole table with one query

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…

Execute Oracle cursor with input parameters in PHP

I am having difficulty figuring out how to add data as input to an Oracle cursor being sent to a stored procedure of a package in PHP.
I am trying to send 2 pieces of data through a cursor. I have verified the data is correct up to sending.
PHP Code:
$finalpieces = explode('|',$lkeyarr[$i]); //0=unique id, 1=table
$conn = oci_connect($oracleUsername,$oraclePassword,$oracleService);
$stmt = OCIParse($conn,"BEGIN PROD.PKG_CORE_OBSERVER.StuckPages_Unlock(:cur_PageDetails); END;");
$cur = oci_new_cursor($conn);
OCIBindByName($stmt,':cur_PageDetails',$cur,-1,OCI_B_CURSOR);
ociexecute($stmt,OCI_DEFAULT);
Stored Procedure Details:
PROCEDURE StuckPages_Unlock
(
cur_PageDetails IN OUT SYS_REFCURSOR
)
accepts ref cursor that includes 2 fields:
ProcessID NUMBER(2);
PageUniqueID NUMBER(10);
Any help would be greatly appreciated.
A Ref Cursor is a pointer to a result set. We cannot assign values to a Ref Cursor, we use it with a query:
open my_ref_cursor for
select process_id, page_unique_id
from some_table;
So, your approach is wrong. It is difficult to be sure what you're trying to achieve but I think what you want is a stored procedure which accepts two parameters that it uses to query a table and return a ref cursor. Perhaps, something like this:
PROCEDURE StuckPages_Unlock
(
p_proc_id in some_table.process_id%type
, p_page_id in some_table.page_unique_id_id%type
, cur_PageDetails OUT SYS_REFCURSOR
)
IS
open PageDetails for
select *
from some_table
where process_id = p_proc_id
and page_unique_id = p_page_id;
END;

Categories