Multi database schema migration (php/mysql) - php

I have an application where each user has their own database and share the same schema. (I have another thread discussing this, so I don't need any information on this)
When migrating the databases, I wrote a script shown below:
<?php
$sql = <<<SQL
ALTER TABLE xyz....;
ALTER TABLE abc.....;
SQL;
$sql_queries = explode(";", $sql);
$exclude_dbs = array();
$conn = mysql_connect("localhost", "USER", "PASSWORD");
$show_db_query = mysql_query('SHOW databases');
$databases = array();
while ($row = mysql_fetch_assoc($show_db_query))
{
if (!in_array($row['Database'], $exclude_dbs))
{
$databases[] = $row['Database'];
}
}
foreach($databases as $database)
{
mysql_select_db($database, $conn);
echo "Running queries on $database\n***********************************\n";
foreach($sql_queries as $query)
{
if (!empty($query))
{
echo "$query;";
if (!mysql_query($query))
{
echo "\n\nERROR: ".mysql_error()."\n\n";
}
}
}
echo "\n\n";
}
?>
It has been working fine without any problems. I then use stepancheg / mysql-diff to make sure the database schemas are good.
Are there any things I should be doing when migrating databases? (I test on a staging server before hand also)

Your approach seems to be working, and the use of mysql-diff is good. Have you considered using mysqldump to back up actual data? It's a more conventional approach than a custom script.

Related

How to make infinite "while" loop in php

I want to create service which every second checking incoming orders in database and doing some stuff. Now I'm using php5.6 and mysql but I'm not sure this is good for that.
Sorry for my code, but now I'm doing like this:
for ($x=0; $x < 999999999999; $x++)
{
$query1 = mysql_query("SELECT * FROM `orders`");
while ($row = mysql_fetch_assoc($query1)) {
//doing some stuff here
}
sleep(1);
}
It works about 12 hours and when crashing with error.
Is there better solution for that or maybe is better to choose different language ?
Your 999999999999 will get reached.
Try something like this:
<?php
$link = mysqli_connect("localhost", "username", "password", "database");
if(!$link) {
die("Could not connect to MySQL database.");
}
while(1) {
$query = "SELECT * FROM YOUR_TABLE";
$res = mysqli_query($link, $query);
if(!$res) {
die("Could not execute query: " . mysqli_error($link));
}
while($row = mysqli_fetch_assoc($res)) {
// Do stuff here
}
sleep(1);
}

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.

Does PHP have a construct similar to .NET's DataSet?

How can I implement a DataSet in PHP like .NET?
I want this class to read data from database only once, then I should be able to use the data without connecting again to MySQL to run queries.
select * from user
When I run this query on the DataSet the data is fetched from memory.
How can I implement this mechanism in PHP?
You could push your data into an array like this:
$result = mysql_query( 'select * from user' );
$results = array();
while ( $row = mysql_fetch_array( $result ) ) {
array_push( $results, $row );
}
mysql_close();
Then you can do whatever operations you want on the array...
foreach( $results as $record ){
$foo = $record['col_name'];
//...
}
What you are describing is the DataSet / DataTable data container classes of .NET which can work in disconnected mode.
A DataReader is kind of a cursor and needs to have the connection open in order to move through the result set of the underlying query.
In PHP you could do this:
<?PHP
$user_name = "root";
$password = "";
$database = "addressbook";
$server = "127.0.0.1";
$db_handle = mysql_connect($server, $user_name, $password);
$db_found = mysql_select_db($database, $db_handle);
if ($db_found) {
$SQL = "SELECT * FROM tb_address_book";
$result = mysql_query($SQL);
while ($db_field = mysql_fetch_assoc($result)) {
print $db_field['ID'] . "<BR>";
print $db_field['First_Name'] . "<BR>";
print $db_field['Surname'] . "<BR>";
print $db_field['Address'] . "<BR>";
}
mysql_close($db_handle);
}
else {
print "Database NOT Found ";
mysql_close($db_handle);
}
?>
I don't think php can provide what you're looking for as it's very much text code and HTML driven, so you don't get the fancy GUI objects like you do in .net. PEAR provides a lot of source code that will produce data grids, that you could possibly investigate, all stored in code like arrays etc. I'm relatively new to php, so maybe someone would disagree...

Help with mysqli and multiple queries

I've never had to use mysqli until today and cannot seem to get this right. What I want is a simple function that will accept a mysql procedure call and have it return those results.
When I started using these procedures, I noticed that the old way of querying the database, using mysql_query, would no longer get me the expected results; one procedure would successfully return and the other would not. After reading the manual and several other examples out there, I found that the reason for this odd behavior was because the results need to be buffered then cleared. I have tried several ways of doing this and have been unsuccessful.
What I have so far works if I create another instance of the mysqli object and will get me both results however, I don't think it's right that I should have to instantiate 20 different objects to get back 20 different queries.
Again, what I want here, is to have a single function that I can feed a procedure to and have the results returned back.
$mysqli = new mysqli('host','user','password','test');
$rs = $mysqli->query('CALL titles()');
while($row = $rs->fetch_object())
{
print_r($row);
}
$mysqli2 = new mysqli('host','user','password','test');
$rs2 = $mysqli2->query('CALL colours()');
while($row2 = $rs2->fetch_object())
{
print_r($row2);
}
you can make a class for this:
db.php // A db class. Call this you perform a query.
<?php
class MyConnection{
var $db_host = 'Localhost';
var $db_user = 'mYUserName';
var $db_password = 'myPassword';
var $db_name = 'mYDB';
var $connection;
function Connect(){
$this->connection = #mysqli_connect($this->db_host, $this->db_user, $this->db_password)
or
die("Error: ".mysqli_connect_error());
mysqli_select_db($this->connection, $this->db_name);
mysqli_query($this->connection, "SET NAMES 'utf8'");
}
function Disconnect(){
mysqli_close($this->connection);
}
function ExecSQL($query){
$result = mysqli_query($this->connection, $query)
or
die('Error: '.mysqli_error($this->connection));
return $result;
}
}
?>
Implementation:
include "db.php";
$conn = new MyConnection;
$conn->Connect();
$rs = $conn->ExecSQL('CALL titles()');
while($row = $rs->fetch_object())
{
print_r($row);
}
$rs2 = $conn->ExecSQL('CALL colours()');
while($row2 = $rs2->fetch_object())
{
print_r($row2);
}
$conn->Disconnect();

How can i synchronize two database tables with 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.

Categories