Copy a large table to a different table efficiently - php

There is a large table and I need to move the contents of it to a table which has a different structure. The tables are on different databases. For this I am using a PHP script. But the script does not work with the way I wanted. It over-copies and never stops. Maybe it is a noobish and simple question but right now my head is spinning, from trying but I can not put my finger on the problem. And this job needs to be done immediately. I will be glad if you help. Here the code snippet:
function copy_table()
{
$this->load->database();
$num_rows = $this->db->get('orj_table')->num_rows();
$offset = 0;
$limit = 500;
while ($offset <= $num_rows)
{
$this->load->database();
//Query for original table
//......
$this->db->limit($limit, $offset);
$records = $this->db->get('orj_table')->result_array();
$this->db->close();
//Open a connection to new database.
$this->db_new = $this->load->database('new', TRUE);
foreach($records as $record)
{
$data1 = $record['data1'];
$data2 = $record['data2'];
$datas[] = array('data1 => $record['data1'],
'data2 => $record['data2']
);
}
//Insert 500 records at one time with "insert_batch"
$sorgu = $this->db_yeni->insert_batch('new_table', datas);
$this->db->close();
$offset += 500;
}
}

Try using this simple mysql query instead :
INSERT INTO different_table (SELECT col1, col3, col4 FROM initial_table)

Why use PHP, or most importantly CodeIgniter?
You should just do something along the lines of:
CREATE TABLE `newtable`
SELECT * FROM `othertable`;
.. of course with this you can select what you want, join, define new column names etc, and whatever you select out will be placed into a new table.
If your destination table already exists, change the CREATE to INSERT.

Related

Condition-driven INSERT and UPDATE in a single query

I have a MySQL table with the following fields:
ID
PHONE
NAME
CITY
COUNTRY
Using PHP, I am reading a comma separated dump of values off a text document, parsing the values and inserting records to the table. For reference, here's the code:
<?php
// Includes
require_once 'PROJdbconn.php';
// Read comma-separated text file
$arrindx = 0;
$i = 0;
$filehandle = fopen(PROJCDUMPPATH.PROJCDUMPNAME,"rb");
while (!feof($filehandle)){
$parts = explode(',', fgets($filehandle));
$contnames[$arrindx] = $parts['0'];
$contnumbers[$arrindx] = preg_replace('/[^0-9]/','',$parts['1']);
$arrindx += 1;
}
fclose($filehandle);
$arrindx -= 1;
$filehandle = NULL;
$parts = NULL;
// Build SQL query
$sql = "INSERT INTO Contact_table (PHONE, NAME) VALUES ";
for ($i = 0; $i < $arrindx; ++$i){
$sql .= "('".$contnumbers[$i]."', '".$contnames[$i]."'),";
}
$i = NULL;
$arrindx = NULL;
$contnames = NULL;
$contnumbers = NULL;
$sql = substr($sql,0,strlen($sql)-1).";";
// Connect to MySQL database
$connect = dbconn(PROJHOST,PROJDB,PROJDBUSER,PROJDBPWD);
// Execute SQL query
$query = $connect->query($sql);
$sql = NULL;
$query = NULL;
// Close connection to MySQL database
$connect = NULL;
?>
Now, this code, as you can see, blindly dumps all records into the table. However, I need to modify the code logic as such:
Read text file and parse records into arrays (already doing)
For each record in text file
Check if PHONE exists in the table
If yes,
For each field in the text file record
If text file field != NULL
Update corresponding field in table
Else
Skip
If no,
INSERT record (already doing)
I apologize if the logic isn't terribly clear, feel free to ask me if any aspect confuses you. So, I understand this logic would involve an insane number of SELECT, UPDATE, and INSERT queries, depending on the number of fields (I intend to add more fields in future) and records. Is there any way to either somehow morph them into a single query or leastwise optimize the code by minimizing the number of queries?
What you're trying to do is called an "upsert" (update/insert).
MySQL INSERT else if exists UPDATE

Get detailed field information for a pgsql resultset in php

I have been trying to get the complete meta information for the fields in a result set from Postgresql in php (something like mysql_fetch_field(), which gives a lots of info about the field definition). While I am able to use the following functions to find some information:
$name = pg_field_name($result, 1);
$table = pg_field_table($result, 1);
$type = pg_field_type($result, 1);
I could not find a way to get more details about whether the field allow null values, contains blob data (by field definition), is a primary,unique key by definition etc. The mysql_fetch_field() gives all of this information somehow, which is very useful.
I would really like some way to get that information from php directly, but if that is not possible, then maybe someone has created a routine that might be able to extract that info from a pgsql resultset somehow.
PS: This looks promising, but the warning on the page is not a good sign:
http://php.net/manual/en/pdostatement.getcolumnmeta.php
Also, I am not using PDO at the moment, but if there is no solution, then a PDo specific answer will suffice too.
You can find the metadata on you column with a query like this:
select * from information_schema.columns
where table_name = 'regions' and column_name = 'capital'
This should provide all of the information found in mysql_fetch_field. I'm not a php coder, so perhaps someone knows of a function that wraps this query.
All;
Was amazed to find pgsql does not have a column count routine in PHP. The helps I looked up all got total count from "information_schema.columns", which is not what you want when doing cell by cell processing.
So here is a couple of quick functions to use:
// Test Cell by Cell
echo "Testing Cell by Cell! <br>";
$sql = "SELECT * FROM sometable;
$res = pg_query($sql);
$r_cnt = pg_numrows($res) or die("Error: Row Count Failed!");
$c_cnt = pg_numcols($res) or die("Error: Col Count Failed!");
echo "C=> $c_cnt R=> $r_cnt <br>";
for ($n=1; $n<=$r_cnt; $n++) {
for ($x=1; $x<=$c_cnt; $x++) {
echo "Cell=> pg_result($res,$n,$x) <br>";
} // end while $x
} // end while $n
function pg_numcols($res) {
$spos = strpos(strtoupper($this->db_sql),'SELECT')+6;
$fpos = strpos(strtoupper($this->db_sql),'FROM');
$lenp = $fpos - $spos;
$t_str = substr($this->db_sql,$spos,$lenp);
$x_str = explode(',',trim($t_str));
$result = count($x_str);
return $result;
} // end function
Hope you enjoy!

Use a PHP function on MySql Column

I have 4 columns in my database. Atk,Str,Dex,and Con. Each being INT and then I have a PHP function get_level that takes those 4 columns and determines the correct level for them. I'm trying to select all users in a given range based on these "levels". The get_combat function takes those 4 values and finds the users combat level. This is what I have, which doesn't work.
<?PHP
$query = "SELECT get_level(attack) as atk,
get_level(strength) as str,
get_level(dexterity) as dex,
get_level(constitution) as con,
get_combat(atk,str,dex,con) as level
FROM `users`
WHERE level > 5 AND level < 10";
?>
Is there a way to do this?
What you are trying to do is impossible. MySQL doesn't even know what PHP is or which language is talking to it.
Why not fetch the values and call your function on in in the loop where you iterate over the results?
Depending on how complex the function is you could also create a stored procedure in your database. You cannot write PHP code in that function though.
I think you can't do something like this in SQL. After executing the query you can use the functions. Assuming you are using the old mysql_* functions:
<?php
$result = mysql_query($query);
$newResults = array();
$i = 0;
while( $row = mysql_fetch_assoc($result) ) {
$newResults[$i]['atk'] = get_level($row['attack']);
$newResults[$i]['strength'] = get_level($row['strength']);
/** ect. **/
$newResults[$i]['level'] = get_combat($newResults['atk'],$newResults['str'],$newResults['dex'],$newResults['con']);
}

Function to get a DISTINCT row

There are lots of articles on getting distinct rows through a sql statement but I havent found the help I need after a SQL statement has already run. Im very new to PHP and I am using the DHTMLX library to render a grid. The unusual syntax used to render the grid is throwing me off big time. What I want is simply distinct rows in my grid only. Everything works great, I just need help getting a function together that will return distinct rows. In my code below I managed to get the two functions that are commented out to work great so I have been using them as a roadmap but I just can't pull the "distinct function" together due to a lack of familiarity with loops. Can someone help me with the syntax needed to have this function return distinct rows. I think array_unique will come into play but Im pretty lost at this point.
<?php
require("codebase/grid_connector.php");
$res = mysql_connect("localhost", "1newuser", "");
mysql_select_db("supplydb");
function distinct($result)
{
$grab = array_unique($rows->get_value("group"));
}
/*function formatting($row){
$data = $row->get_value("gpo_item");
if ($data == 1)
$row->set_value("gpo_item",Yes);
else
$row->set_value("gpo_item",No);
} */
/*function calck($action){
$data1 = $action->get_value("list_price");
$data2 = $action->get_value("sugg_price");
$sum = (($action->get_value("sugg_price") / $action->get_value("list_price")) - 1) * 100 ;
$sum2 = round($sum);
$sum3 = abs($sum2);
$action->set_value("discount",$sum3);
} */
$gridConn = new GridConnector($res, "MySQL");
//$gridConn->event->attach("beforeRender","formatting");
//$gridConn->event->attach("beforeRender","calck");
$gridConn->event->attach("beforeRender", "distinct");
$gridConn->render_sql("SELECT * FROM manufacturers JOIN submissions on manufacturers.manufacturer_id=submissions.manufacturer_id JOIN products on products.product_id=submissions.product_id JOIN product_group on submissions.category=product_group.id", "submission_id", "date,man_name,group,requesting_clinician, requesting_clinician_email, contract_number");
?>
All array_unique does is eradicates duplicate values within a given array.
Why can you not just specify a distinct lookup within your sql?

how to identify the source table of fields from a mysql query

I have two dynamic tables (tabx and taby) which are created and maintained through a php interface where columns can be added, deleted, renamed etc.
I want to read all columns simulataneously from the two tables like so;-
select * from tabx,taby where ... ;
I want to be able to tell from the result of the query whether each column came from either tabx or taby - is there a way to force mysql to return fully qualified column names e.g. tabx.col1, tabx.col2, taby.coln etc?
In PHP, you can get the field information from the result, like so (stolen from a project I wrote long ago):
/*
Similar to mysql_fetch_assoc(), this function returns an associative array
given a mysql resource, but prepends the table name (or table alias, if
used in the query) to the column name, effectively namespacing the column
names and allowing SELECTS for column names that would otherwise have collided
when building a row's associative array.
*/
function mysql_fetch_assoc_with_table_names($resource) {
// get a numerically indexed row, which includes all fields, even if their names collide
$row = mysql_fetch_row($resource);
if( ! $row)
return $row;
$result = array();
$size = count($row);
for($i = 0; $i < $size; $i++) {
// now fetch the field information
$info = mysql_fetch_field($resource, $i);
$table = $info->table;
$name = $info->name;
// and make an associative array, where the key is $table.$name
$result["$table.$name"] = $row[$i]; // e.g. $result["user.name"] = "Joe Schmoe";
}
return $result;
}
Then you can use it like this:
$resource = mysql_query("SELECT * FROM user JOIN question USING (user_id)");
while($row = mysql_fetch_assoc_with_table_names($resource)) {
echo $row['question.title'] . ' Asked by ' . $row['user.name'] . "\n";
}
So to answer your question directly, the table name data is always sent by MySQL -- It's up to the client to tell you where each column came from. If you really want MySQL to return each column name unambiguously, you will need to modify your queries to do the aliasing explicitly, like #Shabbyrobe suggested.
select * from tabx tx, taby ty where ... ;
Does:
SELECT tabx.*, taby.* FROM tabx, taby WHERE ...
work?
I'm left wondering what you are trying to accomplish. First of all, adding and removing columns from a table is a strange practice; it implies that the schema of your data is changing at run-time.
Furthermore, to query from the two tables at the same time, there should be some kind of relationship between them. Rows in one table should be correlated in some way with rows of the other table. If this is not the case, you're better off doing two separate SELECT queries.
The answer to your question has already been given: SELECT tablename.* to retrieve all the columns from the given table. This may or may not work correctly if there are columns with the same name in both tables; you should look that up in the documentation.
Could you give us more information on the problem you're trying to solve? I think there's a good chance you're going about this the wrong way.
Leaving aside any questions about why you might want to do this, and why you would want to do a cross join here at all, here's the best way I can come up with off the top of my head.
You could try doing an EXPLAIN on each table and build the select statement programatically from the result. Here's a poor example of a script which will give you a dynamically generated field list with aliases. This will increase the number of queries you perform though as each table in the dynamically generated query will cause an EXPLAIN query to be fired (although this could be mitigated with caching fairly easily).
<?php
$pdo = new PDO($dsn, $user, $pass, array(PDO::ATTR_ERRMODE=>PDO::ERRMODE_EXCEPTION));
function aliasFields($pdo, $table, $delim='__') {
$fields = array();
// gotta sanitise the table name - can't do it with prepared statement
$table = preg_replace('/[^A-z0-9_]/', "", $table);
foreach ($pdo->query("EXPLAIN `".$table."`") as $row) {
$fields[] = $table.'.'.$row['Field'].' as '.$table.$delim.$row['Field'];
}
return $fields;
}
$fieldAliases = array_merge(aliasFields($pdo, 'artist'), aliasFields($pdo, 'event'));
$query = 'SELECT '.implode(', ', $fieldAliases).' FROM artist, event';
echo $query;
The result is a query that looks like this, with the table and column name separated by two underscores (or whatever delimeter you like, see the third parameter to aliasFields()):
// ABOVE PROGRAM'S OUTPUT (assuming database exists)
SELECT artist__artist_id, artist__event_id, artist__artist_name, event__event_id, event__event_name FROM artist, event
From there, when you iterate over the results, you can just do an explode on each field name with the same delimeter to get the table name and field name.
John Douthat's answer is much better than the above. It would only be useful if the field metadata was not returned by the database, as PDO threatens may be the case with some drivers.
Here is a simple snippet for how to do what John suggetsted using PDO instead of mysql_*():
<?php
$pdo = new PDO($dsn, $user, $pass, array(PDO::ATTR_ERRMODE=>PDO::ERRMODE_EXCEPTION));
$query = 'SELECT artist.*, eventartist.* FROM artist, eventartist LIMIT 1';
$stmt = $pdo->prepare($query);
$stmt->execute();
while ($row = $stmt->fetch()) {
foreach ($row as $key=>$value) {
if (is_int($key)) {
$meta = $stmt->getColumnMeta($key);
echo $meta['table'].".".$meta['name']."<br />";
}
}
}

Categories