The stored procedures must return their first resultset in the form:
(
[index] int,
[id] varchar(50)
)
where
[index]
is 0,1,2,3,... and[id]
is the name of the struct.
As long as the first resultset returns the names of the resultsets in the same order they are returned by the stored procedure the php struct will store each struct in the struct by it's name.
Example ResultSet 0:
0,'resultsets'
1,'codes'
2,'listings'
3,'users'
Example Function Call:
$struct = genericMultiResults('exec dbo.genericProcedure');
Example Results:
$struct['resultsets'][0]; // 'resultsets'
$struct['resultsets'][1]; // 'codes'
foreach($struct['codes'] as $code) { // loop over the records of the codes resultset
...
}
foreach($struct['listings'] as $listing) { /* loop over the records of the listings resultset */
...
}
Implementation:
function genericMultiResultSet($sql) {
global $conn;
// resultset holder
$resultSets = array();
// resultsets key name, can be changed by record 0 of resultset 0
$resultSetsKey = 'resultsets';
// current resultset name, only used by resultsets 1 and above, not by 0, defaults to name of 0
$resultSetKey = 'resultsets';
// execute multi-resultset procedure or sql statement
$results = sqlsrv_query($conn,$sql);
// assume we have the first resultset, loop over resultsets
do {
// loop over rows in resultset
while($row = sqlsrv_fetch_array($results,SQLSRV_FETCH_ASSOC)) {
// if the structure is $row['index'], $row['id'] then assume it is a resultsets key
if(isset($row['index']) && isset($row['id']) && count($row) == 2) {
// if resultsets key not created yet, create it
if(count($resultSets) == 0) {
$resultSets[$row['id']] = array();
// assume first record in resultset describes itself (the resultset, not the row)
$resultSetsKey = $row['id'];
}
// add entry to resultsets key
$resultSets[$resultSetsKey][$row['index']] = $row['id'];
// otherwise, not a resultsets key
} else {
// if no array for current $resultset create it
if(!isset($resultSets[$resultSetKey])) {
$resultSets[$resultSetKey] = array();
}
// add row to it's resultset within $resultSets
array_push($resultSets[$resultSetKey],$row);
}
}
// get next key for next resultset
if(isset($resultSets[$resultSetsKey][count($resultSets)])) {
$resultSetKey = $resultSets[$resultSetsKey][count($resultSets)];
}
// get next resultset
} while(!is_null(sqlsrv_next_result($results)));
sqlsrv_free_stmt($results);
return $resultSets;
}
So my implementation works perfectly, does exactly what I want, lets me edit the procedures (add remove resultsets at will) and I only have to modify my php that uses the function, I never have to touch the function.
So my question: Is there a more elegant implementation to get the same result, ie, reference the resultsets by name set in first resultset, rather than referencing them by the order they are returned?
empty()
instead of comparingcount()
to zero. Declare$resultSetsKey
before initializing$resultSets
, then use$resultSetsKey
instead of$row[ 'id' ]
so that you use the same key throughout the application and don't cause confusion. Don't usearray_push()
, just append like so$resultSets[ $resultSetKey ] [] = $row
. Assuming no other answers are forth coming I'll give this another crack later. – mseancole Jul 19 '12 at 16:27