Migrate data to many-to-many using sql/php - php

I am trying to convert my not so well structured mysql article data to a better many-to-many structure.
basically I have on article table with fields 'article_id, title, author_1, author_2, author_3, ... , author_10' where article id is unique and the author fields hold full names.
What I need is a manay-to-many relationship where I end up with an article table of 'article_id, title' an intermediate table which holds 'article_id, author_id' and an author table which holds 'author_id, author_name'.
I know there must be a way to do this with a few lines of code. I have tried all day with puling the data out and trying to match arrays in php but getting nowhere.
Any help would be much appreciated.

It's pretty straightforward:
Outer loop selects all article rows from the existing table
For each of the author columns, insert a row into the authors table
After each insert, use mysql_insert_id() to get the ID of the inserted row, and insert the relationship into the article/author table.
-
$sql = "SELECT article_id, title, author_1, author_2, author_3, author_4, author_5, author_6, author_7, author_8, author_9, author_10 FROM articles";
$result = mysql_query($sql);
while ($row = mysql_fetch_array($result)) {
for ($i = 1; $i <= 10; $i++) {
if (!empty($row['author_' . $i])) {
$author = mysql_real_escape_string($row['author_' . $i]);
//check if author exists
$check = mysql_query("SELECT author_id FROM authors WHERE author_name = '$author'");
if (mysql_num_rows($check) > 0) {
$author_id = mysql_result($check,0);
} else {
mysql_query("INSERT INTO authors (author_name) VALUES ('$author')");
$author_id = mysql_insert_id();
}
mysql_query("INSERT INTO article_author (article_id, author_id) VALUES ({$row['article_id']}, $author_id)");
}
}
}

Related

loop is increasing each time through select/inserts

I have a script that is pretty straight forward in theory, where I"m trying to select relational data on a development DB2 database, and insert into a separate production db2 server (creating new IDs and relationships on the production side in the process).
So in this script, I:
Select from the dev ITEM table
Store the original primary key
insert the data into the dev ITEM table
Get the ID of the newly inserted one
select SUBITEM from dev with the original ID
for each subitem I insert the data into the prod SUBITEM table with the newly created ITEM ID as the relationship
The problem is the script actually runs successfully, but as it goes, it simply increases by one so even though it inserts each ITEM correctly, it ends up just getting EVERY subitem in the database and storing the original (1st row's) ID. FOr instance:
My first ITEM select returns ID 1204. By the time I let it run for several items, my ITEM table shows records with IDs: 1204,1205,1206 and 1207
That's correct, but when I look at the subITEMS table, I have 10 subITEM records all with itemID of 1204. So it got the right subitem for each iteration of ITEMS but only ever inserted the very first newID variable.
What did I do wrong here:
if($DB2connDEV && $DB2connPROD){
$getDevItems = "
SELECT
itemt_ID,
DESCRIPTION
FROM itemt
";
$stmt = odbc_exec($DB2connDEV, $getDevItems);
while($gettingDevItems = odbc_fetch_array($stmt)){
$rows[] = $gettingDevItems;
}
foreach($rows as $row){
$prepInsert = odbc_prepare($DB2connPROD, "INSERT INTO itemt (itemt_id, description) VALUES(?,?)");
$originalID = $row['itemt_ID'];
$description = $row['DESCRIPTION'];
$insertTable = odbc_execute($prepInsert, array($description));
//Get newly created ID
$getIdentity = "SELECT IDENTITY_VAL_LOCAL() AS LASTID FROM SYSIBM.SYSDUMMY1";
$stmt = odbc_exec($DB2connPROD, $getIdentity);
$row = odbc_fetch_array($stmt);
$newID = $row['LASTID'];
if($newID) {
echo "Last Insert ID is : " . $newID . "\n";
} else {
echo "No Last insert ID.\n";
}
//Get subItems and insert
$getSubItems = "SELECT NAME, DESCRIPTION
FROM SUBITEMT
WHERE itemt_ID = $originalID";
$selectSubItems = odbc_exec($DB2connDEV, $getSubItems);
while($gettingSubItems = odbc_fetch_array($selectSubItems)){
$subItemRows[] = $gettingSubItems;
}
foreach($subItemRows as $subItemRow){
$subItemPrepInsert = odbc_prepare($DB2connPROD, "INSERT INTO subitemt (itemt_id, NAME, DESCRIPTION) VALUES(?,?,?)");
$subItemName = $subItemRow['NAME'];
$subItemDescription = $subItemRow['DESCRIPTION'];
$subtaskInsertExec = odbc_execute($subtaskPrepInsert, array($newID, $subItemName, $subItemDescription));
//get newly created ID for subitem
$getsubtaskID = "SELECT IDENTITY_VAL_LOCAL() AS LASTID FROM SYSIBM.SYSDUMMY1";
$subtaskIDSTMT = odbc_exec($DB2connPROD, $getsubtaskID);
$newsubItemRow = odbc_fetch_array($subtaskIDSTMT);
$newSubItemID = $newsubItemRow['LASTID'];
if($newSubItemID) {
echo "Last Insert subItem ID is : " . $newSubItemID . "\n";
} else {
echo "No Last insert subItem ID.\n";
}
}
}
odbc_close($DB2connPROD);
odbc_close($DB2connDEV);
}
The problem is that you're not clearing out $subItemRows between iterations of the main loop. So each time you're adding the new subitems to the subitems from the previous iterations.
Put
$subItemRows = array();
before the loop:
while($gettingSubItems = odbc_fetch_array($selectSubItems)){
$subItemRows[] = $gettingSubItems;
}

PHP/SQL: Faster Way to Combine Query Results

I'm joining data from two SQL queries and I'm wondering if there is a faster way to do this as a single SQL query because there is a lot of looping involved. I've got two queries that look for different string values in the "option_name" field:
$sql01= "SELECT user_id, option_value FROM wp_wlm_user_options WHERE option_name = 'wpm_login_date' ORDER BY user_id";
$sql02 = "SELECT user_id, option_value FROM wp_wlm_user_options WHERE option_name ='stripe_cust_id' ORDER BY user_id ";
Then I create two arrays:
//Process the 1st SQL query data into an Array
$result_array01 = array();
$j = 0;
while($r = mysql_fetch_assoc($result01)) {
if(!empty($r['option_value'])){
//User Id and Last Login
$result_array01[$j]['user_id'] = $r['user_id'];
$result_array01[$j]['last_login'] = $r['option_value'];
$j++;
}
}
//Process the 2nd SQL query data into an Array
$result_array02 = array();
$k = 0;
while($s = mysql_fetch_assoc($result02)) {
if(!empty($s['option_value'])){
//User Id and Stripe Customer Id
$result_array02[$k]['user_id'] = $s['user_id'];
$result_array02[$k]['cust_id'] = $s['option_value'];
$k++;
}
}
And finally, I combine the arrays:
//Combine the SQL query data in single Array
$combined_array = array();
$l = 0;
foreach($result_array01 as $arr01){
// Check type
if (is_array($arr01)) {
//mgc_account_print("hello: " . $arr01['user_id'] . "\r\n");
foreach($result_array02 as $arr02){
// Check type
if (is_array($arr02)) {
//Check if User Id matches
if($arr01['user_id'] == $arr02['user_id']){
//Create Array with User Id, Cust Id and Last Login
$combined_array[$l]['user_id'] = $arr01['user_id'];
$combined_array[$l]['last_login'] = $arr01['last_login'];
$combined_array[$l]['cust_id'] = $arr02['cust_id'];
$l++;
}
}
}
}
}
Why you doing in two different queries?
Use mysql IN('val', 'val2');
$sql01= "SELECT tbl1.user_id, tbl1.option_value FROM wp_wlm_user_options as tbl1 WHERE tbl1.option_name = 'wpm_login_date'
union all
SELECT tbl2.user_id, tbl2.option_value FROM wp_wlm_user_options as tbl2. WHERE tbl2.option_name ='stripe_cust_id' ";
But using OR/AND will your help you in your case , I didnt see at first that you want combined same table. I didnt delete my answer to help you for another solution
Also you should use DISTINCT to avoid multiple records.
SELECT DISTINCT USER_ID, OPTION VALUE FROM TABLE

Reading a comma seperated data column, and using results to display rows from a different table

Just a little bit stumped at the moment about best way to get the desired result i'm chasing.
So in my users table there is a column name "gshowcase" This field will have a series of numbers separated by a comma.
These numbers refer to the UID (auto increment) in my "games" table.
So if a user has the games ("4,5,9,15,25") it will display thoses rows on there profile from the games table.
Not sure if i have describe this very well lol
EDIT-----------------------------
Where am i going wrong???
function getGrelationsList() {
// The query to select the gamesid from the relations table
$query = sprintf("SELECT `game` FROM `grelations` WHERE `user` = '%s'", $this->db->real_escape_string($this->id));
// Run the query
$result = $this->db->query($query);
// The array to store the gameids the user plays
$gamesplayed = array();
while($row = $result->fetch_assoc()) {
$gamesplayed[] = $row['game'];
// Close the query
$result->close();
// Return the games info list (e.g: 13,22,19)
return implode(',', $gamesplayed);
}
function getGshowcase() {
// The query to select Games info based on gameids returned in previous function
$query = sprintf("SELECT `idu`, `title`, `image`, `url`, `desc` FROM `games` WHERE `idu` = $gamesplayed");
// Run the query
$result = $this->db->query($query);
// The array to store the games info
$gshowcase = array();
while($row = $result->fetch_assoc()) {
$gshowcase[] = $row['idu','title','image','url','desc'];
}
// Close the query
$result->close();
// Return the games info list (e.g: 13,22,19)
return implode(',', $gshowcase);
}
function sidebarGames($type, $for) {
global $LNG;
$result = $this->Gshowcase;
$title = $LNG['subshowcase'];
$r = 'showcase';
// If the select was made
if($for == 0) {
$i = 0;
$output = '<div class="sidebar-container widget-'.$r.'"><div class="sidebar-content"><div class="sidebar-header">'.$title.' <span class="sidebar-header-light">('.$result[1].')</span></div>';
foreach($result[0] as $row) {
if($i == 6) break; // Display only the last 6 Games
// Add the elements to the array
$output .= '<div class="sidebar-subscriptions"><div class="sidebar-title-container"><div class="sidebar-title-name">'.$row['title'].'</div></div><img src="'.$this->url.'/thumb.php?src='.$row['image'].'&t=a&w=112&h=112" /></div>';
$i++;
}
$output .= '</div></div>';
} elseif($for == 1) {
$output = '<strong>'.$result[1].' '.$LNG['people'].'</strong>';
}
return $output;
}
Regards
Rhys
The schema design you chosen can be improved to tackle your problem effectively. There must be MANY-TO-MANY relationship between userDB and gamesDB (assuming these are tables instead of dbs :P).
Using many-to-many approach you can you will have intermediate table say user_games for mapping which will have userDB's primary key and gamesDB's primary key as its own composite primary key.
Now as I am working on ORM in java. Using this kind of schema I can directly have list of gamesDB objects inside userDB instance. Else I can iterate over each row from user_games for the user and prepare object for each associated game and set this list of games into userDB's object.
And now convert this userDB's object in JSON using any open-source lib and return it to client. The returned json may be following format
{
'userid' : 1,
//other user info...
games_list : [
{
'idu' : 1,
'title': 'Counter strike...',
//other info...
},
{
'idu' : 2,
'title': 'H1Z1',
//other info...
},
//Other associated games
]
}
Now in javascript you can easy iterate over this json and render the view.
If it is not possible to change DB schema. you can still use this approach. But now you need to first make an array of game_ids by splitting gshowcase by comma and then iterate over each id and get the game row from db and prepare game object from this.

PHP, SQL - getting fetch where table id = user id and count other table where row is = user id

Thanks for helping, first I will show code:
$dotaz = "Select * from customers JOIN contracts where customers.user_id ='".$_SESSION['user_id']."' and contracts.customer_contract = ".$_SESSION['user_id']." order by COUNT(contracts.customer_contract) DESC limit $limit, $pocetZaznamu ";
I need to get the lists of users (customers table) ordered by count of contracts(contracts table)
I tried to solve this by searching over there, but I can't... if you help me please and explain how it works, thank you! :) $pocetZanamu is Number of records.
I need get users (name, surname etc...) from table customers, ordered by number of contracts in contracts table, where is contract_id, customer_contract (user id)..
This should do it where is the column name you are counting.
$id = $_SESSION['user_id'] ;
$dotaz = "Select COUNT(`customer_contract`) AS CNT, `customer_contract` FROM `contracts` WHERE `user_id`=$id GROUP BY `customer_contract` ORDER BY `CNT` DESC";
Depending on what you are doing you may want to store the results in an array, then process each element in the array separately.
while ($row = mysqli_fetch_array($results, MYSQL_NUM)){
$contracts[$row[1]] = $row[0];
}
foreach ($contracts AS $customer_contract => $count){
Process each user id code here
}
Not sure what you are counting. The above counts the customer_contract for a table with multiple records containing the same value in the customer_contract column.
If you just want the total number of records with the same user_id then you'd use:
$dotaz = "Select 1 FROM `contracts` WHERE `user_id`=$id";
$results = $mysqli->query($dotaz);
$count = mysql_num_rows($results);

Mysql find result_id where name = "x" then delete other entries that share that result_id and name="y"

I'm using a mixture of php and mysql to do the following query and I'm sure there must be a way to do it in just SQL. I've stripped out some of the code and left enough that you should be able to see what I'm trying to accomplish.
Any help would be much appreciated!
SELECT result_id FROM categories
WHERE name = "conventional"
foreach ( $results as $row ){
$query = "
DELETE FROM categories
WHERE result_id = $row->result_id && (name = 'va' OR name = 'fha' OR name = 'usda' OR name = 'other')
";
$this->db($query);
}
EDIT: From the answers I've received so far, I don't think I've explained this well enough. the columns in this table are id, result_id, name
There are multiple entries that share the same result_id as they relate to entries in the "results" table. So I'm trying to find the result_id's of entries with the name "conventional" so I can find all the entries with the same result_id and delete them if their names are "va", "fha", "usda" or "other"
DELETE FROM categories
WHERE name IN ("va", "fha", "usda", "other")
AND result_id IN (
SELECT result_id FROM categories
WHERE name = 'conventional'
)
You want to avoid delete query in loop and here is how to do it:
SELECT result_id FROM categories
WHERE name = "conventional"
// Now build csv of ids
$arx = array();
foreach ( $results as $row ) {
$arx[] = $row->result_id;
}
if(!empty($arx)) {
$arx_1 = implode(',', $arx);
$query = "DELETE FROM categories
WHERE result_id in ({$arx_1}) AND (name = 'va' OR name = 'fha' OR name = 'usda' OR name = 'other')";
$this->db($query);
}

Categories