This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
Dynamically bind mysqli_stmt parameters and then bind result (PHP)
can any one help me on how could I create a dynamic bind_result on PHP.
My query field doesn't know how many fields are there since it was created dynamically (e.g creating year fields base on the date range). below is my script and highlighted on where is the problem.
public function getMarketingReports($datefrom,$dateto)
{
$yearfrom = date("Y", strtotime($datefrom));
$yearto = date("Y", strtotime($dateto));
//create year fields
$concatYear = "";
for($year=$yearfrom;$year<=$yearto;$year++){
$concatYear .= "SUM(IF(c.datecreated='".$year."',IF(LOWER(c.fullTimeEployeeType)='basic hour rate', c.fullTimeEployeeTypeAmount*2080 , c.fullTimeEployeeTypeAmount),0)) ".$year.",";
}
$reportdata = array();
$db = Connection::Open();
$stmt = $db->stmt_init();
if($stmt->prepare("SELECT p.Code `PositionCode`,
p.name `PositionName`,
l.value `Location`,
".$concatYear."
SUM(b.field205) `TotalEmployees`
FROM c1 c
INNER JOIN b1 b
ON c.registrationid=b.id
INNER JOIN positions p
ON c.positionid=p.id
INNER JOIN lookupvalues l
ON c.location=l.id
WHERE c.`status`!=2
AND c.datecreated BETWEEN ? AND ?
GROUP BY c.positionid,c.location,YEAR(c.datecreated)")){
$datefrom = $datefrom." 00:00:00";
$dateto = $dateto." 23:59:59";
$stmt->bind_param("ss",$datefrom,$dateto);
$stmt->execute();
$stmt->bind_result
(
$positionCode,
$positionName,
$location,
**//getting bind result data here for year fields**
$totalEmployees
);
while($stmt->fetch())
{
$surveydata = array();
$surveydata['positionCode'] = $positionCode;
$surveydata['positionName'] = $positionName;
$surveydata['location'] = $location;
**//storing of data here for year fields**
$surveydata['totalEmployees'] = $totalEmployees;
array_push($reportdata,$surveydata);
}
}
Connection::Close();
return $reportdata;
}
Is it possible? Can anyone help me on how could I solve this problem
To start, your code that generates the year fields has a nice syntax error:
"SUM(IF(c.datecreated='".$year."',IF(LOWER(c.fullTimeEployeeType)='basic hour rate', c.fullTimeEployeeTypeAmount*2080 , c.fullTimeEployeeTypeAmount),0) ".$year.","
The SUM( opening statement is missing a closing parentheses. On top of that, you have a floating ".$year." that isn't part of any of the enclosed methods (though, it could be used as an alias; I'm not used to seeing it without a preceeding AS though - so this could be my mistake). To take a guess, I would say to replace the ".$year." with a ) and that should fix that part:
$concatYear .= "SUM(IF(c.datecreated='".$year."',IF(LOWER(c.fullTimeEployeeType)='basic hour rate', c.fullTimeEployeeTypeAmount*2080 , c.fullTimeEployeeTypeAmount),0)),";
If the $year addition is in fact to be an alias, you could add the closing parentheses immediately before it to close the SUM() function.
Regarding dynamically binding the variables, my ideal solution actually comes from a similar question/answer on SO (this is a direct copy/paste and I take no credit for it, but I do like it =P):
// Get metadata for field names
$meta = $stmt->result_metadata();
// This is the tricky bit dynamically creating an array of variables to use
// to bind the results
while ($field = $meta->fetch_field()) {
$var = $field->name;
$$var = null;
$fields[$var] = &$$var;
}
// Bind Results
call_user_func_array(array($stmt,'bind_result'),$fields);
// Fetch Results
$i = 0;
while ($stmt->fetch()) {
$results[$i] = array();
foreach($fields as $k => $v)
$results[$i][$k] = $v;
$i++;
}
You have to call_user_func_array:
call_user_func_array(array($stmt, "bind_result"), $argArray);
And you fill $argArray this way:
$years = array();
$concatYear = "";
for($year=$yearfrom;$year<=$yearto;$year++){
$concatYear .= "SUM(IF(c.datecreated='".$year."',IF(LOWER(c.fullTimeEployeeType)='basic hour rate', c.fullTimeEployeeTypeAmount*2080 , c.fullTimeEployeeTypeAmount),0) ".$year.",";
// track the years you need
$years[] = $year;
}
...
//you prepare all the vars here
$argArray = array(
$positionCode,
$positionName,
$location
);
//loop the years
foreach($years as $y)
{
$argArray[] = ${$y};
}
$argArray[] = $annualSalary;
$argArray[] = $totalEmployees;
$argArray[] = $yearOfData;
And you do stuff with years later this way:
...
foreach($years as $y)
{
$surveydata[$y] = ${$y};
}
Related
Closed. This question is not reproducible or was caused by typos. It is not currently accepting answers.
This question was caused by a typo or a problem that can no longer be reproduced. While similar questions may be on-topic here, this one was resolved in a way less likely to help future readers.
Closed 3 years ago.
Improve this question
I'm doing a triple loop to insert values on an array (dataArray[]).
The first one, search for workers
The second one is a "for" for each day of the week
The last one look if the person works this day.
I don't know why it show me only 1 result....
If I change the order (first $sql) it shows me another entry.
// display loop
$sql = "SELECT workers.id, workers.surname, workers.name
FROM workers,employment_contract
WHERE employment_contract.fk_company_teams_id='".$teamID."'
AND employment_contract.fk_workers_id=workers.id
AND employment_contract.initial_date<'".$beginingDate."'
AND (employment_contract.final_date>".$beginingDate."
OR employment_contract.final_date='0000-00-00-00:00:00')
ORDER BY workers.surname ASC";
$stmt = $db->prepare($sql);
$i=-1;
$dataArray;
if($stmt->execute()){
while ($row = $stmt->fetch(PDO::FETCH_ASSOC)) {
$i++;
// datas in array
$nameInitial = substr($row['name'], 0, 1).'.';
// inserting worker name on array
$dataArray[$i]['workerName']=$nameInitial.' '.$row['surname'];
$workerID = $row['id'];
$totalTime = new DateTime('0000-00-00 00:00:00');
for($j=0;$j<7;$j++){
// changing the current date
$incrementation = 'P'.$j.'D';
$currentDate = date_create($beginingDate);
$currentDate->add(new DateInterval($incrementation));
$currentDate = date_format($currentDate, 'Y-m-d');
// sql search for daily timesheet
$sql = "SELECT initial_date,final_date
FROM working_days
WHERE fk_workers_id='".$workerID."'
AND (initial_date >='".$currentDate." 00:00:00.000')
AND (final_date <='".$currentDate." 23:59:59.999')
ORDER BY id ASC";
$stmt = $db->prepare($sql);
$k=1;
if($stmt->execute()){
while ($row = $stmt->fetch(PDO::FETCH_ASSOC)){
// formatting date for calculation
$time1 = utf8_encode(strftime("%R",strtotime("$row[initial_date]")));
$time2 = utf8_encode(strftime("%R",strtotime("$row[final_date]")));
$initialDate = new DateTime(date($row['initial_date']));
$finalDate = new DateTime(date($row['final_date']));
$time3 = $initialDate->diff($finalDate);
$timeFormatted = $time3->format('%H:%I');
$totalTime->add($time3);
// setting the day to implement
if($j==0){$day = 'monday';}
if($j==1){$day = 'tuesday';}
if($j==2){$day = 'wednesday';}
if($j==3){$day = 'thursday';}
if($j==4){$day = 'friday';}
if($j==5){$day = 'saturday';}
if($j==6){$day = 'sunday';}
$arrayBox = $day.$k;
// inserting day value on array
$dataArray[$i][$arrayBox] = $time1.' '.$time2.' <b>'.$timeFormatted.'</b></div><br>';
unset($time1);
unset($time2);
$k++;
}
}
}
$totalTimeFormatted = $totalTime->format('H:i');
// inserting holidays value on array
$dataArray[$i]['holidays'] = 'Vac';
// inserting sum value on array
$dataArray[$i]['sum'] = $totalTimeFormatted;
// if no timesheet is found for the worker we don't show anything
if($totalTimeFormatted==='00:00'){
unset($dataArray[$i]);
}
unset($totalTime);
}
}
I think my dates (dateTime) calculations are not efficient but it's not the problem here.
As mentionned in commentary, I used same variable name for sql statements $stmt.
I corrected it to $stmt1 for the third loop and it's working.
this is my first time using the site. I need some help. When I run this code and get the output I get duplicated lines of data. So for instance a member maybe on the list 3 - 4 times depending on how many years he has gone to the events. I need to somehow combine any similar data into one row, if that makes sense? So John Doe should not be on the list 7 times just once with all the years he has gone.
$query_mem = "SELECT m.id, m.prefix, m.first_name, m.middle_name, m.last_name, m.suffix, m.member_class, m.jurisdiction_associated,
event.year,
m_event.attend
FROM members AS m, event AS event, members_event AS m_event $where
AND m.member_class IN (1,3)
AND m.id = m_event.codigo_usuario AND m_event.type_event = event.codigo_inscricao
ORDER BY event.year, m.jurisdiction_associated, m.last_name, m.first_name";
$retorno_mem = $conexao->query($query_mem);
if(($conexao->errorCode() == '0') && ($retorno_mem->rowCount() > 0))
{
while($registros_mem = $retorno_mem->fetch(PDO::FETCH_ASSOC))
{
$prefix=$fname=$mname=$lname=$suffix=$address_1=$address_2=$city=$state=$zip=$country=$org=$campaign=NULL;
$member_id = ($registros_mem["id"]);
$prefix = ($registros_mem["prefix"]);
$fname = ($registros_mem["first_name"]);
$mname = ($registros_mem["middle_name"]);
$lname = ($registros_mem["last_name"]);
$suffix = ($registros_mem["suffix"]);
$class = getMemberClassName($conexao,$registros_mem["member_class"]);
$jurisdiction = getJurisdictionName($conexao,$registros_mem["jurisdiction_associated"]."000");
$year = ($registros_mem["year"]);
$attendance = getMemberAttendanceName($conexao,$registros_mem["attend"]);
$data1[] = array(
''.utf8_encode((int)$member_id).'',
''.utf8_encode($prefix).'',
''.utf8_encode($fname).'',
''.utf8_encode($mname).'',
''.utf8_encode($lname).'',
''.utf8_encode($suffix).'',
''.utf8_encode($class).'',
''.utf8_encode($jurisdiction).'',
''.utf8_encode($year).'',
''.utf8_encode($attendance).'',
);
}
}
You can use the member's ID as the array key to see if he's already been, and if so just add to the year field. Something like this:
while($registros_mem = $retorno_mem->fetch(PDO::FETCH_ASSOC))
{
if ( ! array_key_exists( $registros_mem['id'], $data1)
{
// We need to make year an array so it can hold multiple years.
$registros_mem['year'] = [$registros_mem['year']];
$data1[$registros_mem['id']] = $registros_mem;
} else {
$data1[$registros_mem['id']]['year'][] = $registros_mem['year'];
}
}
0I have three arrays... example:
phonenums
[0] 555-5555
[1] 555-4444
[2] 555-3333
types
[0] cell
[1] home
[2] work
notes
[0] a note
[1] the babysitters name
[2] call before 6pm
They come from a form with dynamically added inputs, so the number of rows is arbitrary.
I want to put these arrays into a table in MySQL, using PHP
Table name: customerphones
id
customer_id
phone
type
notes
I can get any single array into the database fine, but, when it comes to putting in all three to coordinate with each other (ex: each row[0] to be in one row of the database table)....I'm stuck! I keep rewriting it in different loops or whatnot, and it comes out wrong every time.
I can post my code if it helps explain my situation further. I am just looking for a "concept" here though, to point me in the right direction.
Should I combine the arrays somehow?, or put them into a loop? I don't know!
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Here is my solution I came up with (as requested). I'm sure it is not practical at all...and there is probably a much better way to do it. But it got my desired result.
// ~~~ Get variables from the form submitted
$phonenums = $_POST["phone"];
$types = $_POST["type"];
$notes = $_POST["notes"];
// ~~~ Queries for Inserting Customer Phone Numbers
$querynum = "INSERT INTO customerphones";
$querynum .= "(customer_id, phone)";
$querynum .= "VALUES (?, ?)";
$stmtnum = mysqli_prepare($db, $querynum);
$queryty = "UPDATE customerphones SET ";
$queryty .= "type = ? ";
$queryty .= "WHERE customer_id = ? AND phone = ?";
$stmtty = mysqli_prepare($db, $queryty);
$queryno = "UPDATE customerphones SET ";
$queryno .= "notes = ? ";
$queryno .= "WHERE customer_id = ? AND phone = ?";
$stmtno = mysqli_prepare($db, $queryno);
// Loops for executing the queries to insert phone numbers
// (I scraped this together b/c I couldn't get other methods to work...Change this later)
$n = 0;
foreach($phonenums as $rowph) {
mysqli_stmt_bind_param($stmtnum, 'is', $custid, $rowph);
mysqli_execute($stmtnum);
$rct = 0;
foreach($types as $rowty) {
if($rct == 0) {
$x = $types[$n];
mysqli_stmt_bind_param($stmtty, 'sis', $x, $custid, $rowph);
mysqli_execute($stmtty);
$rct++;
}
} // End Update Phone Type
$rct = 0;
foreach($notes as $rowno) {
if($rct == 0) {
$x = $notes[$n];
mysqli_stmt_bind_param($stmtno, 'sis', $x, $custid, $rowph);
mysqli_execute($stmtno);
$rct++;
}
} // End Update Phone Notes
$n++;
} // End foreach loops
Well, I'm gonna take a shot in the dark here.
Using PDO with PreparedStatements, MultipleIterator and ArrayIterator:
$dbh = new PDO("mysql:host=localhost;dbname=YOUR_DATABASE;", "root", "");
$sth = $dbh->prepare("INSERT INTO customerphones(phone, type, notes) VALUES(:phone, :type, :note)");
$m = new MultipleIterator();
$m->attachIterator(new ArrayIterator($phonenums), 'phones');
$m->attachIterator(new ArrayIterator($types), 'types');
$m->attachIterator(new ArrayIterator($notes), 'notes');
foreach($m as $row){
$sth->bindParam(":phone", $row[0]);
$sth->bindParam(":type", $row[1]);
$sth->bindParam(":note", $row[2]);
$sth->execute();
}
I'm assuming that you're using a local MySQL server, and your server's root account isn't password protected.
This works like this:
Create a new PDO connection with some parameters;
Prepare a statement with some placeholders for an insert;
Create an Iterator to unite the arrays;
Attach all the arrays to the iterator;
Go through all the iterations of the iterator: Every iteration returns a array with a phone number, a type and a note;
Bind all the elements of the current iteration to the placeholders of the statement and then execute it.
But please post what you're using to connect to the DB, then I'll refactor my answer.
using mysqli:
$host = 'your_host';
$user = 'your_user';
$pass = 'your_pass';
$db = 'your_database';
$mysqli = new mysqli($host, $user, $pass, $db);
// Check connection mysql
if ($mysqli->connect_error) {
die('Connect Error (' . $mysqli->connect_errno . ') '
. $mysqli->connect_error);
}
$sql = 'INSERT INTO customerphones(phone, type, notes) VALUES(?,?,?)';
$stmt = $mysqli->prepare($sql);
$stmt->bind_param('sss', $phone, $type, $note);
$index = 0;
while(COUNT($phonenums) - 1 >= $index){
$phone = $phonenums[$index];
$type = $type[$index];
$note= $note[$index];
$stmt->execute();
$index++;
}
This question already has answers here:
Echo a comma on all but the last value? (result from mysql_fetch_array)
(11 answers)
Why doesn't it prevent further looping?
(2 answers)
Closed 8 years ago.
I am trying to make sure that commas go after all of the items EXCEPT for the last one - I am trying to figure out how to calculate out what the last item is for variable lists. I decided to try to use count($variablename) but it doesn't seem to work.
Is there something wrong with my syntax?
$servicearray = mysql_query("select serv_id from org_serv_xref where org_id='".$org_id."'");
$servi = 0;
while ($servicearrayrow = mysql_fetch_array($servicearray)) {
$servdescarray = mysql_query("select serv_desc from service where serv_id='".$servicearrayrow['serv_id']."'");
while ($servdescarrayrow = mysql_fetch_array($servdescarray)) {
if ($servi < 5 OR $servi < count($servdescarrayrow)) {
ECHO $servdescarrayrow['serv_desc'].",";
$servi++;
}
else if ($servi == 5 OR $servi == count($servdescarrayrow)) {
echo $servdescarrayrow['serv_desc'];
$servi++;
}
else {
$servi = 0;
break 2;
}
}
}
Because you're starting $servi at 0. It will always be less than the count of the array. If you start it at 1 it should work the way you expect it to.
change your query to
$servicearray = mysql_query("select GROUP_CONCAT(serv_id) from org_serv_xref where org_id='".$org_id."'");
now sql builds the nice comma delimited list for you :)
As near as I can figure, your trying to do something like this (although I could be totally wrong):
// Initialise vars
$lastid = '';
$items = array();
// Do the query
$query = "SELECT serv_desc, serv_id
FROM service
WHERE serv_id IN (
SELECT serv_id
FROM org_serv_xref
WHERE org_id='".$org_id."'
)
ORDER BY serv_id";
$servdescarray = mysql_query($query);
while ($servdescarrayrow = mysql_fetch_assoc($servdescarray)) {
// We've reached the next ID, echo the result of the last one.
if ($lastid != $servdescarrayrow['serv_id']) {
$lastid = $servdescarrayrow['serv_id'];
if (count($items)) {
echo implode(',',$items);
$items = array();
}
}
if (count($items) == 5) { // We don't want more than 5 items
continue;
} else { // Add an item to the results
$items[$servdescarrayrow['serv_desc']];
}
}
// Make sure we get the last one
if (count($items)) {
echo implode(',',$items);
}
I have this function in my CMS, which inserts a variable list of fields and values into two different tables; one is a static index table and one is dynamic. This is the function:
function insertFields($fields)
{
$stdfields = array();
$extfields = array();
/* Separate the fields based on if the fields is standard or extra. $this->fields is a csv list of the defined extra fields */
foreach($fields as $field => $value)
{
$fields[mysql_real_escape_string($field)] = mysql_real_escape_string($value);
if(strstr($this->fields, $field))
$extfields[$field] = $value;
else
$stdfields[$field] = $value;
}
//Build the 2 queries -- Maybe there is a better way to do this?
$extfieldcount = count($extfields);
$stdfieldcount = count($stdfields);
$stditers = 0;
$extiters = 0;
foreach($extfields as $field => $value)
{
if($extiters != $extfieldcount)
{
$extfields.= $field.", ";
$extvalues.= "'".$value."', ";
}
else
{
$extfields.= $field." ";
$extvalues.= "'".$value."' ";
}
$extiters++;
}
foreach($stdfields as $field => $value)
{
if($stditers != $stdfieldcount)
{
$newfields.= $field.", ";
$newvalues.= "'".$value."', ";
}
else
{
$newfields.= $field." ";
$newvalues.= "'".$value."' ";
}
$stditers++;
}
//Inset the standard fields
$stdquery = "INSERT INTO masteridx (".$newfields.") VALUES (".$newvalues.")";
$this->dbQuery($stdquery);
/* not perfect. I need a better way to find the id that was inserted, so I can combine three queries into at least two */
$findlastquery = "SELECT `id` FROM `masteridx` WHERE `slug`='".$fields['slug']."' LIMIT 1";
$result = $this->dbQuery($findlastquery);
$result = mysql_fetch_assoc($result);
$tempfield = "id, ";
$tempvalue = "'".$result['id']."', ";
//Insert the extra fields
$extquery = "INSERT INTO ".$this->type." (".$tempfield.$extfields.") VALUES (".$tempvalue.$extvalues.")";
$this->dbQuery($extquery);
}
So for a prepared statement, I can't Bind the fields, just the values, right? So I would still have to escape the fields if I did something like:
for ($i = 0; $i <= $stdfieldcount; $i++)
{
if($i < $stdfieldcount)
$qs.= '?, ';
else
$qs.= '? ';
}
$sth = $dbh->prepare("INSERT INTO masteridx ({$stdfields}) VALUES ({$qs})");
$sth->execute($array_of_stdfield_values);
What's the point here if I still have to escape the fields? This function will eventually take an array of multiple articles and their fields. The fields themselves would be different each time, as well.. I figured that when I first looked at prepared statements, I could just hand it an array of fields, and an array of values, but I guess that's not the case.
My question is really, how would you all accomplish this? I would like to start being database agnostic, and PDO looked like a great way to do this.
PHP provides quite a few convenience functions that do a lot of the stuff you're doing by hand.
PDO supports named parameters in your SQL statements, so you can then pass a key/value array where the keys match your named parameter placeholders.
The join() function is very useful for building comma-separated lists.
Many functions exist to manipulate arrays.
Some functions allow you to give a callback (which can be a closure in PHP 5.3), to process arrays dynamically.
Example (not tested):
function insertFields($fields) {
$columns = join(",", array_map(
function($col) { return "`".preg_replace("/`/gu","``",$col)."`"},
array_keys($fields)));
$params = join(",", array_map(
function($col) { return ":".preg_replace("/[`\s]/gu","",$col)},
array_keys($fields)));
$stdquery = "INSERT INTO masteridx ({$columns}) VALUES ({$params})";
$stmt = $pdo->prepare($stdQuery);
$stmt->execute($fields);
}