Insert result from DOMXpath into MySQL - php

Im using this DOMXpath query to retrieve some columns from another page.
$html = file_get_contents("http://localhost:8888/stockPrices.php");
libxml_use_internal_errors(true);
$doc = new \DOMDocument();
if($doc->loadHTML($html))
{
$result = new \DOMDocument();
$result->formatOutput = true;
$table = $result->appendChild($result->createElement("table"));
$thead = $table->appendChild($result->createElement("thead"));
$tbody = $table->appendChild($result->createElement("tbody"));
$table->setAttribute('class', 'table table-hover');
$xpath = new \DOMXPath($doc);
$newRow = $thead->appendChild($result->createElement("tr"));
foreach($xpath->query("//table[#id='kurstabell']/thead/tr/th[position()=2 or position()=3 or position()=8 or position()=9 or position()=10]") as $header)
{
$newRow->appendChild($result->createElement("th", trim($header->nodeValue)));
}
foreach($xpath->query("//table[#id='kurstabell']/tbody/tr") as $row)
{
$newRow = $tbody->appendChild($result->createElement("tr"));
foreach($xpath->query("./td[position()=2 or position()=3 or position()=8 or position()=9 or position()=10]", $row) as $cell)
{
$newRow->appendChild($result->createElement("td", trim(htmlentities($cell->nodeValue))));
}
}
echo $result->saveXML($result->documentElement);
}
This generates four columns, aktier, senaste, högst, lägst and omsatt. But i dont know how to insert this to a MySQL table. Im thinking to first generate a array of the result, like:
Array
(
[1] => stdClass Object
(
[aktie] => AAK AB
[senaste] => 634,50
[högst] => 638,50
[lägst] => 622,50
[omsatt] => 32 094 048
)
[2] => stdClass Object
(
[aktie] => ABB Ltd
[senaste] => 162,80
[högst] => 163,30
[lägst] => 161,90
[omsatt] => 167 481 268
)
(you get the hang of it..)
)
According to this image:
And then loop the array into the table. Something like this?
$sql = "INSERT INTO stock_list (`aktie`, `senaste`, `högst`, `lägst`, `omsatt`, `timestamp`) VALUES
(:aktie, :senaste, :högst, :lägst, :omsatt)";
$query = $database->prepare($sql);
foreach($data as $stock){
$query->execute(array(':aktie' => $stock->stock,
':senaste' => $stock->prevclose,
':högst' => $stock->high,
':lägst' => $stock->low,
':omsatt' => $stock->volume
));
}
My question:
How do i populate the array with data?
How do i loop the result in a mysql query?

Don't know if this is a work around. But it is currently doing what I'm asking for.
// build query...
$sql = "INSERT INTO stocks";
// columns to insert into...
$sql .="(`name`, `closing`, `high`, `low`, `turn`, `timestamp`)";
// implode values of $array...
// notice array_chunk, this functions splits a big array into multi.
$str = NULL;
foreach (array_chunk($a, 5) as $row) {
$str .= '("'. implode('","',$row).'",NOW()),';
}
// Remove last ',' (comma) from string
// We added commas in the previous step
$str = rtrim($str,',');
$sql .= 'VALUES '. $str ;
// execute query...
$app = new Connection();
$query = $app->getConnection()->prepare($sql);
$query->execute();
if ($query->rowCount() <= 0) {
echo "Something went wrong.";
return false;
}
return true;

My guess is that what you really want is something along the lines of:
$query = 'INSERT INTO stock_list
(`aktie`, `senaste`, `högst`, `lägst`, `omsatt`, `timestamp`)
VALUES
(:aktie, :senaste, :högst, :lägst, :omsatt, NOW())';
$stmt = $app->getConnection()->prepare($query);
foreach ($data as $stock) {
$stmt->execute(
[
':aktie' => $stock->aktie,
':senaste' => $stock->senaste,
':högst' => $stock->{'högst'},
':lägst' => $stock->{'lägst'},
':omsatt' => $stock->omsatt,
]
);
$stmt->closeCursor();//might be required depending on DB driver, not for MySQL, though
}
Note that I call NOW() in the query string, and I don't bind that SQL function call to the parameters I execute the prepared statement with. All in all though, a timestamp field is best set by the DB itself (with a DEFAULT CURRENT_TIMESTAMP in the field definition). Then you can just leave the timestamp field out of your INSERT query, and it'll be set correctly for you.
I've also changed the way you're using the objects stock. From the var_dump I can see the properties aren't called stock, high, low and all that. The problem is, some of these property names (lägst for example) are a bit dodgy. You'll probably have to access those using a string, which can be done, like I did, by writing $objVar->{'property name as string'}.
If I were you, though, I'd look into ways of changing what $data actually looks like, and change the property names if at all possible.

Related

Looping through Array Values with $SQL output

I have a list of serialized data that I unserialize and store into an array.
$employee_data = unserialize($entry, '63');
Which results in an expected output:
Array ( [0] =>
Array ( [First] => Joe
[Last] => Test
[Birth Date] => 01/01/2011
)
[1] =>
Array ( [First] => Mike
[Last] => Miller
[Birth Date] => 01/01/1980
)
)
Ive been trying, unsuccessfully, to insert these records into a table in MySQL using foreach() or something like:
$employee_array = array();
$k = 1;
for($n=0; $n<count($employee_data); $n++ ){
$employee_array['employee_first_name'.$k] = $employee_data[$n]['First'];
$employee_array['employee_last_name'.$k] = $employee_data[$n]['Last'];
$employee_array['employee_birthdate'.$k] = $employee_data[$n]['Birth Date'];
$SQL = "INSERT INTO employee_test (
employee_first_name,
employee_last_name,
employee_birthdate
)
VALUES (
'$employee_first_name.$k',
'$employee_last_name.$k',
'$employee_birthdate.$k'
)"
$k++;
};
Each employee in the array needs to be entered into a new row in the table, however the number of employees will vary from 1 to 10+
We've tried
foreach($employee_array as $key => $value)
with the same results.
The actual results we're hoping for is the SQL Statement to be:
insert into employee_test(
employee_first_name,
employee_last_name,
employee_birthdate)
VALUES(
'Joe',
'Test',
'01/01/2011');
insert into employee_test(
employee_first_name,
employee_last_name,
employee_birthdate)
VALUES(
'Mike',
'Miller',
'01/01/1980');
Keep in mind that your sql statement is not escaped. For example, a name with an apostrophe like "0'neil" will break your sql. I would also familiarise yourself with php's foreach: https://www.php.net/manual/en/control-structures.foreach.php.
I'm not sure exactly what you're trying to accomplish by adding the index to the name and sql value, but I would do something like this:
foreach($employee_data as $key => $value){
// $employee_array is not necessary
$employee_array[$key]['employee_first_name'] = $value['First'];
$employee_array[$key]['employee_last_name'] = $value['Last'];
$employee_array[$key]['employee_birthdate'] = $value['Birth Date'];
// Needs escaping
$SQL = "INSERT INTO employee_test (
employee_first_name,
employee_last_name,
employee_birthdate
)
VALUES (
'{$value['First']}',
'{$value['Last']}',
'{$value['Birth Date']}'
)";
echo $SQL;
};
The first implementation wont work as your calling a variable rather than the key in your array.
'$employee_first_name.$k',
Should be
$employee_array['employee_first_name'.$k]
You are also creating the SQL statement every iteration of the for loop, so in this implementation only the last employee will save.
Also I don't see the reasoning in doing it that way anyway you may as well just use the employee_data array and the $k variable can also be made redundant.
$SQL = "";
for($n=0; $n<count($employee_data); $n++ ){
$SQL .= "INSERT INTO employee_test (
employee_first_name,
employee_last_name,
employee_birthdate
) VALUES (";
$SQL .= "'".$employee_data[$n]['First']."',";
$SQL .= "'".$employee_data[$n]['Last']."',";
$SQL .= "'".$employee_data[$n]['Birth Date']."'";
$SQL .= ");";
};
Ive not tested but it should give you an idea.
You will also have issues with the date formatted that way, Your database would likely require the date in yyyy/mm/dd format
Finally I would not recommend inserting values like this, look at the PDO library for placeholders.
I think I understand what you're trying to do here. You are using the = operator, effectively setting $SQL to a new value each time your loop iterates. If you adapt your code, you will be able to append to $SQL variable each time.
//I used this array for testing. Comment this out
$employee_data = array(
0 => array(
"first" => "test",
"last" => "tester",
"birth date" => "01/01/1970"
),
1 => array(
"first" => "bob",
"last" => "david",
"birth date" => "02/02/1972"
),
);
//Start SQL as a blank string
$SQL = "";
//Do your iteration
foreach( $employee_data as $key=>$value ){
$first = $value['first'];
$last = $value['last'];
$birthDate = $value['birth date'];
//append this query to the $SQL variable. Note I use `.=` instead of `=`
$SQL .= "INSERT INTO employee_test(
`employee_first_name`,
`employee_last_name`,
`employee_birthdate`)
VALUES(
'$first',
'$last',
'$birthDate'
);";
}
//output the query
echo $SQL;
There are much easier ways of doing this though. Look into prepared statements :)

Dynamically bind values PDO with foreach() [duplicate]

This question already has answers here:
When to use single quotes, double quotes, and backticks in MySQL
(13 answers)
Closed 5 years ago.
I have a need to generate a MySQL query dynamically, and values of specific types may or may not appear in specific column types. Here is a case for a query generated for two x values and one y value, each of which must be present in either of respective sets of columns (please to not read it too close, since the query itself has been tested extensively and works alright if the proper parameters are inserted manually):
SELECT
*
FROM
TABLE
WHERE
(
/*start of block x0 */
(
(columm_x0 = ':value_type1_index1')
OR (column_x1 = ':value_type1_index1')
OR (column_x2 = ':value_type1_index1')
OR (column_x3 = ':value_type1_index1')
OR (column_x4 = ':value_type1_index1')
)
/* end of block 0*/
/*start of block x1 */
OR (
(columm_x0 = ':value_type1_index2')
OR (column_x1 = ':value_type1_index2')
OR (column_x2 = ':value_type1_index2')
OR (column_x3 = ':value_type1_index2')
OR (column_x4 = ':value_type1_index2')
)
/*end of block x1*/
/*start of block y1*/
AND (
(columm_y0 = ':value_type2_index1')
OR (column_y1 = ':value_type2_index1')
OR (column_y2 = ':value_type2_index1')
OR (column_y3 = ':value_type2_index1')
OR (column_y4 = ':value_type2_index1')
) /*end of block y1*/
)
This whole query is supplied to $query variable.
So each time we must search for values in all specific columns no matter what. The parameters themselves are supplied as array:
$values = Array ( [type1] => Array ( [0] => value1 [1] => value2 )[type2] => Array ( [0] => value3 ))
My PDO looks like the following:
try {
$connect = new PDO("mysql:host=".$db['server'].";dbname=".$db['db'], $db['mysql_login'], $db['mysql_pass'], array(PDO::MYSQL_ATTR_INIT_COMMAND => 'SET NAMES utf8'));
$connect->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
$stmt=$connect->prepare($query);
foreach ($values as $type => $typevalue){
foreach ($typevalue as $element => $elementvalue){
$parameter = ":value_{$type}_index{$element}";
$stmt->bindValue($parameter, $elementvalue, PDO::PARAM_STR);//i think here is the problem!
echo "<br>$parameter = $elementvalue<br>"; //shows exactly correct parameter and value
}
}
if ($stmt->execute() AND $stmt->rowCount() > 0){
echo "success";
//do some stuff
} else {
echo "false".' '. $stmt->rowCount() . '<br>';
$stmt->debugDumpParams();
}
}
catch(PDOException $e) {
echo $e->getMessage();
}
The resulting query using pdo always returns 0 rows although the parameters replaced with values manually result in success.
As i said above, i don't think that bindValue() method allows variables in parameter.
Any help would be appreciated.
All i had to do was to remove the quotes around the parameters in query so this is correct:
(column_x1 = :value_type1_index2)
and this is NOT correct:
(column_x1 = ':value_type1_index2')

How to sort a multidimensional array of columns by a specific column in PHP?

I found on the PHP documentation the function "array_multisort" that is meant to sort an array "of columns". They provide one example where the user has an array of rows and then the user has to transform this array of rows into an array of columns. In my case the array is already set by columns, such as:
tablearray
{
['Employee_ID'] = {0 => row1, 1 => row2, 2 => row3, 3 => row4}
['First_Name'] = {0 => row1, 1 => row2, 2 => row3, 3 => row4}
['LastName'] = {0 => row1, 1 => row2, 2 => row3, 3 =>row4}
}
I want to sort by Employee_ID and I need all the other columns to follow the same order. I tried:
array_multisort($tablearray['Employee_ID'], SORT_ASC);
But it only sorts the first column (which becomes a mess). The array has more than 10 columns and it changes the column names depending on the search (the columns names are its keys).
On PHP's documentation for this function, the example provided shows that the after transforming the rows array into a columns array, we should use the original array as a third parameter to match the keys - I don't have the "original" array to do the match since I didn't transform anything.
Thank you.
Desired output, as suggested by one user:
Original:
array
{
['Employee_ID'] = (1002, 4508, 0002, 1112)
['Business_Unit'] = ('UER', 'ABC', 'XYZ', 'EER')
['LastName'] = ('Smith', 'Vicente', 'Simpson', 'Thompson')
}
Sorted by Employee ID:
array
{
['Employee_ID'] = (0002, 1002, 1112, 4508)
['Business_Unit'] = ('XYZ', 'UER', 'EER', 'ABC')
['LastName'] = ('Simpson','Smith', 'Thompson', 'Vicente')
}
--
My original array is a database query output:
Array
(
[0] => Array
(
[Employee_ID] => 0000
[Supervisor_ID] => 00000
[Location_Descr] => somewhere
[Start_Date] => 06/03/2002
[Service_Date] => 06/03/2002
[Rehire_Date] => 00/00/00
[Business_Unit] => YYYY
[Job_Title] => Manager
[Email] => email#example.com
[Dept_Desc] => bla bla bla
[Employee_Name_LF] => Last, First
[Supervisor_Name_LF] => Last, First
[Term_Date] => 00/00/00
[Preferred_Name] => Someone
[Source] => Sheet2
)
)
There a several more rows.
The main purpose is to show the results as an HTML table and to generate a CSV file. I already made those functions using the modified structure (the first that I posted). I thought it would be easier to deal with that structure... Indeed it was, but not for sorting unfortunately.
The array_multisort documentation (http://php.net/manual/en/function.array-multisort.php) suggests separating each column as an individual array.. However, as you can see I have several columns (and the user can select more or less to be shown before performing the query.. So I can't just list all of them on the statement).
I a willing to change everything just to make the code better to be worked with.
Ugly - would be a lot easier if you formatted the input tables.
$arr = array(
'Employee_ID' => array('1002', '4508', '0002', '1112'),
'Business_Unit' => array('UER', 'ABC', 'XYZ', 'EER'),
'LastName' => array('Smith', 'Vicente', 'Simpson', 'Thompson')
);
$employees = array();
foreach (range(0, sizeof($arr[current(array_keys($arr))]) - 1) as $k) {
$emp = array();
foreach ($arr as $col => $vals) {
$emp[$col] = $arr[$col][$k];
}
$employees[] = $emp;
}
$sort = array();
foreach ($employees as $k => $v) {
$sort[$k] = $v['Employee_ID'];
}
array_multisort($sort, SORT_ASC, $employees);
print_r($employees);
And to put back in the original format:
$arr_sorted = array();
foreach (array_keys($arr) as $col) {
$arr_sorted[$col] = array();
foreach ($employees as $emp) {
$arr_sorted[$col][] = $emp[$col];
}
}
print_r($arr_sorted);
Thank you for posting the extra details in your question, as they did help in understanding the intent of your question.Now, you didn't tell us how that table should look; If you want the employees one per row, or one per column. Which is kind of crucial to know. Normally one would have one employee per line, especially if this is to be exported to CVS. However, I have a suspicion that it's the latter you want. Otherwise you've gone about this in a very overly complicated manner.Point in case: Normal one-per-row layout:
<?php
$db = new PDO();
// Defining the fields we need here, to avoid having too long a string for the query.
$fields = "e.employee_id, e.first_name, e.lastname, u.business_unit, s.email";
// Do the sorting in the database itself. Not only is this faster, but it
// is also a lot easier to sort it exactly as you'd like.
// Note that I don't use prepared statements here, as there is no user-input.
$query = <<<outSQL
SELECT {$Fields} FROM `unit` AS u
INNER JOIN `employee` AS e ON e.employee_id = u.unit_id
INNER JOIN `employee` AS s ON s.employee_id = u.supervisor_id
ORDER BY e.`employee_id`
outSQL;
$data = $db->query($query);
// Creating a printf() template for the output, to make the code easier to maintain.
$rowTemplate = <<<outHTML
<tr>
<td>%1\$d</td>
<td>%2\$s</td>
<td>%3\$s</td>
</tr>
outHTML;
// Generate the table template, using placeholders for where the data will be added..
$tableTemplate = <<<outHTML
<table>
<thead>
<tr>
<th>ID</th>
<th>First name</th>
<th>Last name</th>
</tr>
</thead>
<tbody>
%s
</tbody>
</table>
outHTML;
// Regular table output, one employee per line.
$temp = '';
foreach ($data as $e) {
// hs() is a shortcut function to htmlspecialchars (), to prevent against XSS.
$temp .= sprintf($rowTemplate, $e['employee_id'], hs($e['first_name']), hs($e['lastname']));
}
// Add the rows to the table, so that you can echo the completed product wherever you need.
$employeeTable = sprintf($tableTemplate, $temp);
If you want to do it one per column, it becomes a bit more intricate. Though, still a bit easier than your first attempt. :)
Namely, something like this:
<?php
$db = new PDO();
// Defining the fields we need here, to avoid having too long a string for the query.
$fields = "employee_id, first_name, lastname";
// Do the sorting in the database itself. Not only is this faster, but it
// is also a lot easier to sort it exactly as you'd like.
// Note that I don't use prepared statements here, as there is no user-input.
$data = $db->query("SELECT {$Fields} FROM `employees` ORDER BY `employee_id`");
// We need to know how many columns we'll have. One per employee.
$columns = count ($data);
// Rows have a header in front of each line, and one td tag for each employee.
$rowTemplate = "\t\t<th>%s</th>\n".str_repeat("\t\t\t<td>%s</td>\n", $columns);
// Generate the table template, using placeholders for where the data will be added..
$tableTemplate = <<<outHTML
<table>
<tbody>
%s
</tbody>
</table>
outHTML;
// Reformat the array to give us the data per-column.
$temp = array ();
foreach ($data as $field => $e) {
// Since we've already sorted the data in the database we don't need to do any further sorting here.
// Also note that I'm doing the escaping here, seeing as this array will only be used for output.
$temp['Employee ID'][] = intval($e['employee_id']);
$temp['First name'][] = hs($e['first_name']);
$temp['Last name'][] = hs($e['lastname']);
}
// Now we do the same as in the above example.
$rows = '';
foreach ($temp as $label => $l) {
// We have the label as the first template variable to be added, so put it as the first element.
array_unshift($l, $label);
// Add the current row of items to the output, using the previously established template.
$rows = vprintf($rowTemplate, $l);
}
// Add the rows to the table, so that you can echo the completed product wherever you need.
$employeeTable = sprintf($tableTemplate, $temp);
PS: Haven't tested the code, but it should work.
I ran into his problem and after much angst found a really nice solution in the notes on the php manual page - I now have the following function which i use whenever I need to solve this type of problem.
function fnArrayOrderby(){
//function to sort a database type array of rows by the values in one or more column
//source http://php.net/manual/en/function.array-multisort.php - user notes
//example of use -> $sorted = fnArrayOrderby($data, 'volume', SORT_DESC, 'edition', SORT_ASC);
$args = func_get_args(); //Gets an array of the function's argument list (which can vary in length)
//echo "sorting ".$args[0]."<br>";
if (!isset($args[0])) { return;}
$data = array_shift($args); //Shift an element off the beginning of array
foreach ($args as $n => $field) {
if (is_string($field)) {
$tmp = array();
foreach ($data as $key => $row)
$tmp[$key] = $row[$field];
$args[$n] = $tmp;
}
}
$args[] = &$data;
call_user_func_array('array_multisort', $args);
return array_pop($args);
}

How will PHP Web Service read JSON

My JSON is
{"users":[{"UserName":"user1","FullName":"Name One"},
{"UserName":"user2","FullName":"Name Two"}]}
My PHP is
<?php
include '../inc/connect.php';
include '../inc/class/mysql.class.php';
$data = file_get_contents('php://input');
$array = json_decode($data, true);
$rows = array();
foreach ($array['users'] as $parentvalue)
foreach ($parentvalue as $key => $value)
$rows[] = "('" . $value . "', '" . $value . "')";
$values = implode(",", $rows);
try
{
$count = mysql_query("INSERT INTO users (UserName, FullName) VALUES $values") or die(mysql_error());
}
catch(PDOException $e) { //later
}
?>
The structure of the array is
Array
(
[users] => Array
(
[0] => Array
(
[FullName] => Name One
[UserName] => user1
)
[1] => Array
(
[FullName] => Name Two
[UserName] => user2
)
)
)
Instead of inserting the data:
**user1 - Name One
**user2 - Name Two
to MySQL...
It inserts
**user1 - user1
**Name One - Name One
**user2 - user2
**Name Two - Name Two
Please help!
/********EDIT (prev answer below)*********/
Here is my new code. I have modified your JSON structure based on your comments.
//added addresses as an example (no the postcodes aren't real :P)
$json='{
"users":[
{"UserName":"user1","FullName":"Name One"},
{"UserName":"user2","FullName":"Name 2"}
],
"addresses":[
{"HouseNumber":"1","PostCode":"LS1 1PS"},
{"HouseNumber": "23", "PostCode": "LS1 2PS"}
]
}';
$data=json_decode($json);
//loop over each 'table'
foreach ($data as $table_name=>$data_array){
$table_name=mysql_real_escape_string($table_name);
//loop over each 'row' in table
foreach($data_array as $current_obj){
$current_sql="INSERT INTO ".$table_name." SET ";
$row=array();
//loop through 'row' data and get 'column' name and value.
foreach($current_obj as $name=>$value){
$row[]='`'.mysql_real_escape_string($name).'` = "'.mysql_real_escape_string($value).'"';
}
$current_sql.=implode(',',$row);
mysql_query($current_sql);
unset($current_sql,$name,$value);
}
}
Now, while this code will do what you asked I probably wouldn't use it myself. I would have different endpoints in your web service for the different tables (and use GET,POST,PUT etc http requests to determine action - see REST web services) - Although its more work, clearly defined actions make debugging easier and your application more secure (as you'll know exactly what its doing and what to).
As for authentication, thats a whole issue on its own that I can't really go into here. Please don't think I mean this in an offensive way, but as you're new to development I would advise spending more time learning before trying to make anything production ready - to protect you and your customers more than anything.
Anyway, I hope this helps.
Regards
Ryan
/******* OLD ANSWER - LEFT HERE FOR CLARITY****************/
I believe you don't need the second loop. This is what I have (modify to suit your needs):
$json='{"users":[{"UserName":"user1","FullName":"Name One"},{"UserName":"user2","FullName":"Name 2"}]}';
$data = json_decode($json);
$rows = array();
foreach ($data->users as $user_obj){
$rows[]='("'.$user_obj->UserName.'","'.$user_obj->FullName.'")';
}
$values = implode(",", $rows);
echo "INSERT INTO users (UserName, FullName) VALUES ".$values;
Also, I would advise that you make use of prepared statements or at the very least mysql_real_escape_string.
Hope this helps,
Ryan :)
(P.s I stopped json_decode converting objects to arrays as it feel it is helpful to know when a data structure is supposed to be iterable and when it is not - feel free to change it back if you like.)
I slightly improved your code, for readability's sake. The very first thing you'd realize is that you're dealing with two problems here : one is parsing JSON response, and the second one is inserting records into a table:
$json = '{"users":[{"UserName":"user1","FullName":"Name One"},
{"UserName":"user2","FullName":"Name Two"}]}';
$values = buildArray($json);
insertValues($values);
function buildArray($json) {
$result = array();
$array = array_values(json_decode($json, true));
foreach ($array as $index => $nestedArray) {
foreach($nestedArray as $index => $value) {
$result[] = $value;
}
}
return $result;
}
function insertValues(array $values) {
foreach($values as $index => $array) {
$query = sprintf("INSERT INTO `users` (`UserName`, `FullName`) VALUES ('%s', '%s')",
mysql_real_escape_string($array['UserName']),
mysql_real_escape_string($array['FullName']),
);
if (!mysql_unbuffered_query($query)) {
return false;
}
}
return true;
}

Insert if not exists in DB and delete if not in an array

I have an array like this :
$services = array(
array("id" => "1", "desc" => "desc 1"),
array("id" => "2", "desc" => "desc 2" ),
......
);
I want to insert those services in TABLE_SERVICE .
each service is inserted if it doesnt exists in TABLE_SERVICE , and deleted it if it exists in TABLE_SERVICE but not in $services array.
I could just delete all records in TABLE_SERVICE and then insert all $services elements ,
but that can be an issue with performance because i often have large set of data in both TABLE_SERVICE and $services .
So is there an efficient way to do this ?
Thanks.
If it was me I'd iterate over $services collecting ids:
$ids = array();
foreach($services as $service)
{
$ids[] = $service['id'];
}
Then using PHP's join and the select NOT IN
"DELETE FROM TABLE_SERVICE WHERE id NOT IN (" . join($ids,',') . ")"
After that, iterate over the array again to insert/update using ON DUPLICATE KEY
"INSERT INTO TABLE_SERVICE (id,desc) VALUES (?,?) ON DUPLICATE KEY UPDATE desc = ?"
Since oracle doesn't have ON DUPLICATE KEY this stackoverflow question might help you with that last part.
My answer would be that there isn't really an efficient way to do this.
I have thought about a merge, but to be efficient, you would still be better off first inserting it in a temporary table. Then you might as well just truncate table_service and then fill it again from your $service array.
Even if Kristoffer's anwser could work, it might still be slower than a truncate insert.
This is my php method to quickly insert a lot of records:
The advantage of this is, that your insert statement will be parsed only once instead for each insert, which will improve the speed greatly. Sometimes by a factor 100 or so.
$connection = oci_connect(<YOUR CONNECTION>);
$sql = insert into table_service (id, var) values (:id, :var); // desc is a reserved word, cannot be a column name
$parsed = oci_parse($connection, $sql);
$binds = array(':id', ':var');
$sizes = array(6, 20);
$data = $services;
$errors = execute_multiple($binds, $sizes, $data);
if ($errors > 0)
// log or show
else
// feedback: full succes!
function execute_multiple($binds, $sizes, $data, $commit = true)
{
$errorCount = 0;
// first determine all binds once
foreach ($binds as $i => $bind)
{
// ${trim($bind, ':')} example: :some_id -> $some_id
oci_bind_by_name($parsed, $bind, ${trim($bind, ':')}, $sizes[$i]);
}
// Then loop over all rows and give the variables the new value for that row
// This is because the variables remain binded!
for ($row=0; $row<count($data); $row++)
{
foreach ($binds as $i => $bind)
{
$value = array_key_exists($i, $data[$row]) ? substr($data[$row][$i], 0, $sizes[$i]) : null;
${trim($bind, ':')} = trim($value);
}
if (! #oci_execute($this->parsed, OCI_DEFAULT)) // don't auto commit
$errorCount++;
}
if ($commit)
oci_commit($connection);
return $errorCount;
}

Categories