How can i synchronize two database tables with PHP? - php

I need to use PHP to copy data from one MySQL database to another.
I can build and array of all the values to go into the other database but first I want to make sure the database has the correct fields before inserting.
For example say I am going to be copying data from tableA to tableB.
I can set up tableB to look just like tableA but in the future I may add columns to tableA and forget to add them to tableB, then my PHP script will try to insert data into a column that doesn't exist in tableB and it will fail.
So what I want to do is compare tableA to tableB and any columns that tableA has that tableB doesn't have add them to tableB.
Can anyone tell me how to do this?

Thanks everyone, based on all your help I was able to write a PHP class that copies any columns from table A to table B if they are not already there:
class MatchTable
{
var $_table_one_name;
var $_table_two_name;
var $_table_one_db_user;
var $_table_one_db_pass;
var $_table_one_db_host;
var $_table_one_db_name;
var $_table_two_db_user;
var $_table_two_db_pass;
var $_table_two_db_host;
var $_table_two_db_name;
var $_table_one_columns = array();
var $_table_two_columns = array();
var $_table_one_types = array();
var $_table_two_types = array();
var $_table_one_link;
var $_table_two_link;
var $_isTest;
function MatchTable($isLive = true)
{
$this->_isTest = !$isLive;
}
function matchTables($table1, $table2)
{
$this->_table_one_name = $table1;
$this->_table_two_name = $table2;
if(isset($this->_table_one_db_pass))
{
$this->db_connect('ONE');
}
list($this->_table_one_columns,$this->_table_one_types) = $this->getColumns($this->_table_one_name);
if(isset($this->_table_two_db_pass))
{
$this->db_connect('TWO');
}
list($this->_table_two_columns,$this->_table_two_types) = $this->getColumns($this->_table_two_name);
$this->addAdditionalColumns($this->getAdditionalColumns());
}
function setTableOneConnection($host, $user, $pass, $name)
{
$this->_table_one_db_host = $host;
$this->_table_one_db_user = $user;
$this->_table_one_db_pass = $pass;
$this->_table_one_db_name = $name;
}
function setTableTwoConnection($host, $user, $pass, $name)
{
$this->_table_two_db_host = $host;
$this->_table_two_db_user = $user;
$this->_table_two_db_pass = $pass;
$this->_table_two_db_name = $name;
}
function db_connect($table)
{
switch(strtoupper($table))
{
case 'ONE':
$host = $this->_table_one_db_host;
$user = $this->_table_one_db_user;
$pass = $this->_table_one_db_pass;
$name = $this->_table_one_db_name;
$link = $this->_table_one_link = mysql_connect($host, $user, $pass, true);
mysql_select_db($name) or die(mysql_error());
break;
case 'TWO';
$host = $this->_table_two_db_host;
$user = $this->_table_two_db_user;
$pass = $this->_table_two_db_pass;
$name = $this->_table_two_db_name;
$link = $this->_table_two_link = mysql_connect($host, $user, $pass, true);
mysql_select_db($name) or die(mysql_error());
break;
default:
die('Improper parameter in MatchTable->db_connect() expecting "one" or "two".');
break;
}
if (!$link) {
die('Could not connect: ' . mysql_error());
}
}
function getColumns($table_name)
{
$columns = array();
$types = array();
$qry = 'SHOW COLUMNS FROM '.$table_name;
$result = mysql_query($qry) or die(mysql_error());
while($row = mysql_fetch_assoc($result))
{
$field = $row['Field'];
$type = $row['Type'];
/*
$column = array('Field' => $field, 'Type' => $type);
array_push($columns, $column);
*/
$types[$field] = $type;
array_push($columns, $field);
}
$arr = array($columns, $types);
return $arr;
}
function getAdditionalColumns()
{
$additional = array_diff($this->_table_one_columns,$this->_table_two_columns);
return $additional;
}
function addAdditionalColumns($additional)
{
$qry = '';
foreach($additional as $field)
{
$qry = 'ALTER TABLE '.$this->_table_two_name.' ADD '.$field.' '.$this->_table_one_types[$field].'; ';
if($this->_isTest)
{
echo $qry.'<br><br>';
}
else
{
mysql_query($qry) or die(mysql_error());
}
}
}
/**
* End of Class
*/
}

You could write a function that returns the columns from the table such as this:
function columns($table) {
$columns = array();
$sql = "desc $table";
$q = mysql_query($sql);
while ($r = mysql_fetch_array($q)) {
$columns[] = $r[0];
}
return $columns;
}
Next, you can compare the columns, from the two tables:
function tables_different($table1, $table2) {
$cols1 = columns($table1);
$cols2 = columns($table2);
return count(array_diff($cols1, $cols2)) ? true : false;
}
Now, you can integrate the tables_different() function into your data transfer script, running it each time to make sure the tables are the same.
Of course, you can make this fancier and have it tell you which columns are different between the two tables, making it more useful to synchronizing them.

I'm not a 100% sure this is what you're looking for but I used to do a little database maintenance a while back. We needed a way to make sure the devDB and the prodDB were identical in structure and I tracked down this nifty little tool. The tool creates a sql-alter-script that can be run on the database you would like to patch. It written in perl so I guess it should work cross platform but I have only tried it on linux.
The tool is called mySQLdiff, is freeware and can be downloaded at www.mysqldiff.org.

you could look into some phpclasses that do this for you
http://www.phpclasses.org/search.html?words=mysql+sync&x=0&y=0&go_search=1

SHOW COLUMNS FROM «table»

This is a very complex task and as far as I know many have tried to solved it so far (unfortunately I am not aware of any 100% guaranteed solution).
I'd say that before jumping to implement your own solution you should take a look and read about the challenges you'll be facing by reading about Schema evolution, Schema Refactoring, Schema versioning, etc.
Afterwards, you can take a look at PHP MDB2_Schema (some more documentation in this article).
If you are not tied to PHP then you may also take a look at Sundog which provides a set of advanced schema refactorings.
Once you get a reliable schema migration tool for your app, migrating data will be just a trivial task.
./alex

Probably the easiest way to do this would be
$sql = "SELECT * FROM tableA WHERE 1"
$results = mysql_fetch_assoc($sql);
$sql = "truncate table tableB";
// run truncate
foreach($result as $update){
$sql = "Insert into table b VALUES(....)"
// run insert
}
But you need to be extremely careful here. Make sure that the only process that can write to tableB is the one that does the copy from tableA other wise you will have lost data. Also make sure that nothing can write to tableA once this process has begun.
The best practice for this would be to not do this in php but rather through mysql replication.

Use TOAD for MySQL Schema compare tool, it will look at the tables, show you the differences visually and generate SQL queries to synchronize the tables structure. Also it does data compare.

Related

call data from database without mentioning specific rows

hye, i'm having trouble in calling all the rows in one table. hope anyone could assist me solve the error:
<?php
require_once('database.php');
$result = mysql_query("SELECT * FROM events ");
while($row = mysql_fetch_array($result))
?>
I am not an expert on mysqli stuff (I use a Connection class I found somewhere which provides functions like selectMultipleRows($query) and so on) but I will try to give a good answer here.
assuming you already have created a connection $this->connID
$mysqli = $this->connID;
$result = $mysqli->query($query);
$data = $result->fetch_all(MYSQLI_ASSOC);
//stuff I do to make my life easier:
$return = array(); //for scoping reasons
if (isset($data[0]['id'])) {
foreach ($data as $value) {
$return[$value['id']] = $value;
}
} else {
$return = $data;
}
as far as I am concerned this should work.
edit
my class Connection basically works like this:
$this->connID = new mysqli($this->server, $this->user, $this->pass, $this->database);
if ($this->connID→connect_errno) { //debug stuff
var_dump($this->connID->connect_error);
}
$this->connID->set_charset("utf8");
I guess this is all you will need.

how to acess my database elements using the for loop?

I'm learning PHP and I'm well versed with Java and C. I was given a practice assignment to create a shopping project. I need to pull out the products from my database. I'm using the product id to do this. I thought of using for loop but I can't access the prod_id from the database as a condition to check! Can anybody help me?! I have done all the form handling but I need to output the products. This is the for-loop I am using. Please let me know if I have to add any more info. Thanks in advance :)
for($i=1; $i + 1 < prod_id; $i++)
{
$query = "SELECT * FROM products where prod_id=$i";
}
I would suggest that you use PDO. This method will secure all your SQLand will keep all your connections closed and intact.
Here is an example
EXAMPLE.
This is your dbc class (dbc.php)
<?php
class dbc {
public $dbserver = 'server';
public $dbusername = 'user';
public $dbpassword = 'pass';
public $dbname = 'db';
function openDb() {
try {
$db = new PDO('mysql:host=' . $this->dbserver . ';dbname=' . $this->dbname . ';charset=utf8', '' . $this->dbusername . '', '' . $this->dbpassword . '');
} catch (PDOException $e) {
die("error, please try again");
}
return $db;
}
function getproduct($id) {
//prepared query to prevent SQL injections
$query = "SELECT * FROM products where prod_id=?";
$stmt = $this->openDb()->prepare($query);
$stmt->bindValue(1, $id, PDO::PARAM_INT);
$stmt->execute();
$rows = $stmt->fetchAll(PDO::FETCH_ASSOC);
return $rows;
}
?>
your PHP page:
<?php
require "dbc.php";
for($i=1; $i+1<prod_id; $i++)
{
$getList = $db->getproduct($i);
//for each loop will be useful Only if there are more than one records (FYI)
foreach ($getList as $key=> $row) {
echo $row['columnName'] .' key: '. $key;
}
}
First of all, you should use database access drivers to connect to your database.
Your query should not be passed to cycle. It is very rare situation, when such approach is needed. Better to use WHERE condition clause properly.
To get all rows from products table you may just ommit WHERE clause. Consider reading of manual at http://dev.mysql.com/doc.
The statement selects all rows if there is no WHERE clause.
Following example is for MySQLi driver.
// connection to MySQL:
// replace host, login, password, database with real values.
$dbms = mysqli_connect('host', 'login', 'password', 'database');
// if not connected then exit:
if($dbms->connect_errno)exit($dbms->connect_error);
$sql = "SELECT * FROM products";
// executing query:
$result = $dbms->query($sql);
// if query failed then exit:
if($dbms->errno)exit($dbms->error);
// for each result row as $product:
while($product = $row->fetch_assoc()){
// output:
var_dump($product); // replace it with requied template
}
// free result memory:
$result->free();
// close dbms connection:
$dbms->close();
for($i=1;$i+1<prod_id;$i++) {
$query = "SELECT * FROM products where prod_id=$i";
$result = mysqli_query($query, $con);
$con is the Database connection details
you can use wile loop to loop thru each rows
while ($row = mysqli_fetch_array($result))
{
......
}
}
Hope this might work as per your need..
for($i=1; $i+1<prod_id; $i++) {
$query = "SELECT * FROM products where prod_id = $i";
$result = mysql_query($query);
while ($row = mysql_fetch_array($result, MYSQL_NUM)) {
print_r($row);
}
}
I think you want all records from your table, if this is the requirement you can easily do it
$query = mysql_query("SELECT * FROM products"); // where condition is optional
while($row=mysql_fetch_array($query)){
print_r($row);
echo '<br>';
}
This will print an associative array for each row, you can access each field like
echo $row['prod_id'];

Mysql result as array

I have a php function that interogates a table and gets all the fields in a column if a condition is fulfield. So the function returns a collection of elements.
The problem is that i want this function to return an array that i can parse and display.
The code below:
function get_approved_pictures(){
$con = mysql_connect("localhost","valentinesapp","fBsKAd8RXrfQvBcn");
if (!$con)
{
echo 'eroare de conexiune';
die('Could not connect: ' . mysql_error());
}
mysql_select_db("mynameisbrand_valentineapp", $con);
$all = (mysql_query("SELECT picture FROM users WHERE approved = 1"));
$row=mysql_fetch_assoc($all);
// mysql_close($con);
return $row['picture'];
}
Where am I wrong?
You need to use the loop for traversing all the data fetched by the query:
$pictures=array();
while($row=mysql_fetch_assoc($all))
{
$pictures[]=$row['picture'];
}
return $pictures;
Do it like this
$all = mysql_query("SELECT picture FROM users WHERE approved = 1");
$arr = array(); // Array to hold the datas
while($row = mysql_fetch_array($all)) {
$data = $row['picture'];
array_push($arr,$data);
}
return $arr;
You can now insert it into a function and return the values.
Note : mysql_* functions are being depreciated. Try to avoid them.
For the sake of diversity and to give you some sense of how to use PDO instead of deprecated mysql_*, this is how your function might look like:
function get_approved_pictures(){
$db = new PDO('mysql:host=localhost;dbname=mynameisbrand_valentineapp;charset=UTF-8',
'valentinesapp', 'password');
$query = $db->prepare("SELECT picture FROM users WHERE approved = 1");
$query->execute();
$pictures = $query->fetchAll(PDO::FETCH_ASSOC);
$db = null;
return $pictures;
}
Disclaimer: all error handling intentionally omitted for brevity
For the sake of diversity and to give you some sense of how the things have to be instead of inconvenient and wordy PDO, this is how your function might look like:
function get_approved_pictures(){
global $db;
return $db->getCol("SELECT picture FROM users WHERE approved = 1");
}
Disclaimer: all error handling is up and running but intentionally encapsulated into private methods for invisibility.

PHP5 Mysqli class is not outputting data

So i am trying to make a backup class and this is what I have so far. Issue is the $tbl_data is empty. What am I doing wrong.
The connection to the database is successful.
Without the 'echo $tbl_data', the '$current_table - current table' output is correct but if 'echo $tbl_data' is used, only the first table is shown ( trying to backup two tables to begin with ).
class mBackup{
private $_connection = ""; //db connection var
private $output = ""; //sql output
private $tbl_data = "";
private $tbl_row = "";
private $nfields = "";
private $create_table_query = "";
private $create_table_output = "";
public function __construct($dbhost,$dbname,$dbuser,$dbpassword){
$this->_connection = new mysqli($dbhost,$dbuser,$dbpassword,$dbname);
//possible connection error
if($this->_connection->connect_errno){
echo "Failed to connect to the DB";
}
else{
echo "Connected<br />";
}
}
public function backup_db(){
//get the table names from the DB and store in an array
$result = $this->_connection->query("SHOW TABLES");
//get the TABLE names
while($row = $result->fetch_row())
{
$table_names[] = $row[0];
}
//For each table
foreach($table_names as $current_table)
{
echo $current_table." - current table<br />"; //debug
$tbl_data = "";
$tbl_row = "";
$nfields = "";
$create_table_query = "";
$create_table_output = "";
//SELECT Everything from the table in use
$query = $this->_connection->prepare("SELECT * FROM ?");
$query->bind_param('s', $current_table);
$query->execute();
$query->bind_result($tbl_data);
$query->fetch();
echo $tbl_data."<br/>";
}
}
Try something like:
while ($query->fetch()) {
echo $tbl_data;
}
and see if that gets you anything. From the little that I know, bind_result binds columns in the result set to variables. If your table has 5 columns, you should have bind_result($var1, $var2, $var3, $var4, $var5) but since your number of columns are going to change depending on the table, I don't know if bind_result will give you what you need.
Try closing the prepared statement after every loop
$query->close();
or resetting.
$query->reset()
You can't use ? for the table name. See the second note in http://www.php.net/manual/en/mysqli.prepare.php for the allowed places for markers. So you'll have to construct the query by normal variable interpolateion:
$select = sprintf("SELECT * FROM `%s`", $current_table);
$result = $this->_connection->query($select);

Using PHP to place database rows into an array?

I was just wondering how i would be able to code perform an SQL query and then place each row into a new array, for example, lets say a table looked like the following:
$people= mysql_query("SELECT * FROM friends")
Output:
| ID | Name | Age |
--1----tom----32
--2----dan----22
--3----pat----52
--4----nik----32
--5----dre----65
How could i create a multidimensional array that works in the following way, the first rows second column data could be accessed using $people[0][1] and fifth rows third column could be accessed using $people[4][2].
How would i go about constructing this type of array?
Sorry if this is a strange question, its just that i am new to PHP+SQL and would like to know how to directly access data. Performance and speed is not a issue as i am just writing small test scripts to get to grips with the language.
$rows = array();
while ($row = mysql_fetch_array($result, MYSQL_NUM)) {
$rows[] = $row;
}
Are you open to using a DB module, like the PEAR::DB module? If so, check out this article by Paul Dubois on Writing Scripts with PHP's Pear DB Module. The Module has been superseded, but it will show you the basics of some more advanced (and more commonplace) DB practices.
As for your actual question, you could iterate over all the rows and populate an array...
$dsn = "mysqli://testuser:testpass#localhost/test";
$conn =& DB::connect ($dsn);
if (DB::isError ($conn)) { /* ... */ }
$result =& $conn->query ("SELECT * FROM friends");
if (DB::isError ($result)){ /* ... */ }
while ($row =& $result->fetchRow()) {
$people[] = $row;
}
$result->free ();
Or you could write an object which implements the ArrayAccess interface, requesting a particular row when you refer to that index. (This code could be completely wrong but here's my try)
class FriendsTable implements ArrayAccess {
function offsetGet($key) {
$result =& $conn->query ("SELECT * FROM friends LIMIT $key, 1",); // careful; this is vulnerable to injection...
if (DB::isError ($result)){ die ("SELECT failed: " . $result->getMessage () . "\n"); }
$people = null;
if ($row =& $result->fetchRow ()) {
$people = $row;
}
$result->free ();
return $people;
}
function offsetSet($key, $value) {
/*...*/
}
function offsetUnset($key) {
/*...*/
}
function offsetExists($offset) {
/*...*/
}
}
$people = new FriendsTable();
$person = $people[2]; // will theoretically return row #2, as an array
... or something.
$array = array();
$sql = "SELECT * FROM friends";
$res = mysql_query($sql) or trigger_error(mysql_error().$sql);
while($row = mysql_fetch_assoc($res)) $array[]=$row;

Categories