I am stuck on a query/calculation based on two different tables (joined by a third table). A form collects information to input into tbl2, tbl1 is linked to tbl2 via foreign key. I need to calculate and insert a value into tbl2 based on form data and a value from tbl1.
My Query + Calculation looks like this:
$res = $user->runQuery("SELECT binWeight FROM jobBins jb JOIN butchJobOpen bjo ON bjo.jobBins_binID = jb.binID JOIN butchJobClose bjc ON bjc.butchJobOpen_butchJobNum = bjo.butchJobNum WHERE bjo.butchJobNum = '$butchJobOpen_butchJobNum'");
$res->execute();
$row = $res->fetch(PDO::FETCH_ASSOC);
//Calculate $trimYield
$trimYield = $row['binWeight'] / $trimWeight;
The query should use a form value $butchJobOpen_butchJobNum, verify the bin exists on the join conditions, and return the weight of the bin....this works fine as a standalone query, however, I cannot get any results from my calculation...I am sure I am just missing something stupid...but I am stuck, so I lob this up to the merciless SO community, in hopes that while getting downvoted, someone will point me in the right direction while ridiculing my obvious mistake.
Okay, here is what you have to do
Get rid of all the home-brewed stuff. Instead of whatever $user->runQuery use vanilla PDO.
Verify the input. See whether your variable contain anything useful.
Use PDO properly, utilizing prepared statements.
Make your code to give at least any outcome.
Do realize that above instruction is not a ready to use solution on a golden plate but just steps you have to make yourself to investigate the problem.
So
ini_set('display_errors',1);
error_reporting(E_ALL);
$dsn = "mysql:host=$host;dbname=$db;charset=$charset";
$opt = [PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION];
$pdo = new PDO($dsn, $user, $pass, $opt);
var_dump("that argle-bargle var name I can't type it:",$butchJobOpen_butchJobNum);
$sql = "SELECT binWeight FROM jobBins jb
JOIN butchJobOpen bjo ON bjo.jobBins_binID = jb.binID
JOIN butchJobClose bjc ON bjc.butchJobOpen_butchJobNum = bjo.butchJobNum
WHERE bjo.butchJobNum = ?";
$res = $pdo->prepare($sql);
$res->execute([$butchJobOpen_butchJobNum]);
$binWeight = $res->fetchColumn();
var_dump("bin weight:", $binWeight);
var_dump("trim weight:", $trimWeight);
$trimYield = $binWeight / $trimWeight;
var_dump("finally", $trimYield);
The var_dump part is most essential, giving you a clue what's going on in your program. A 10000 times more fruitful than a hour of staring at the code or a whine on SO.
The point here is to verify every bloody variable's state. And yo see whether it contains anything expected.
To help everyone understand what I'm asking I put forward a scenario:
I have user A on my web app.
There is a particular page which has a table that contains information that is unique to that user. Let's say it is a list of customers that only show for user A because user A and these customers are in region 5.
Other users are assigned to different regions and see different lists of customers.
What I would like to do is cache all of the results for each users list. This isn't a problem as I can use:
$MC = new Memcache;
$MC->addserver('localhost');
$data = $MC->get('customers');
if($data)
{
} else {
$data = $this->model->customersGrid($take, $skip, $page, $pageSize, $sortColumn, $sortDirection, $filterSQL, $PDOFilterParams);
$MC->set('customers', $data);
}
header('Content-Type: application/json');
return $data;
The challenge now is to somehow convert the SQL filter syntax that comes from my users table into a function that can filter and sort an array ($data is a JSON string that I would turn into an array if that's the right way to go).
Just for reference, here is the array of aliases I use for building the WHERE clause in my statements:
$KF = new KendoFilter;
$KF->columnAliases = array(
'theName' => 'name',
'dimensions' => 'COALESCE((SELECT CONCAT_WS(" x ", height, width, CONCAT(length, unit)) FROM products_dimensions,
system_prefs, units_measurement
WHERE products_dimensions.productId = product.id
AND units_measurement.id = system_prefs.defaultMeasurementId), "-")',
'gridSearch' => array('theName', 'basePrice')
);
$filterSQL = $KF->buildFilter();
My question is what is a good way to filter and sort memcache data as if it was an SQL query? Or does memcache have something already built in?
Memcache cannot do this - you can't replace your database with memcache (that is not what it is for), you can only store key => value pairs.
I think a better approach is to store each data for each user in a specific mem cache key.
So for example if user A with $user_id = 123 visits the page:
$data = $MC->get('customers_for_'.$user_id);
This way you only get the customers for user 123.
A more generic approach is to generate a hash for each sql query with it's params (but that might be overkill in most cases). For example if you have a query select ... from ... where a = #a and b = #b with variables $a and $b you could do the following (you must adapt this for kendo of course, but to get the idea):
$query = "select ... from ... where a = #a and b = #b";
# crc32 because it is fast and the mem key does not get too long
$sql_crc = crc32($query.$a.$b);
$data = $MC->get("customers_".$sql_crc);
To rule out (unlikely) hash collisions for different users, you could mix in the user id in the key, too:
$data = $MC->get("customers_for_".$user_id."_".$sql_crc);
BUT: If you start doing this all over the place in your app because otherwise it is too slow, then maybe the problem lies in your database (missing/wrong indexes, bad column definitions, complicated relations, etc.) and time should better be invested in fixing the DB than working around the issue like this.
*MySQL will be upgraded later.
Preface: Authors can register in two languages and, for various additional reasons, that meant 2 databases. We realize that the setup appears odd in the use of multiple databases but it is more this abbreviated explanation that makes it seem so. So please ignore that oddity.
Situation:
My first query produces a recordset of authors who have cancelled their subscription. It finds them in the first database.
require_once('ConnString/FirstAuth.php');
mysql_select_db($xxxxx, $xxxxxx);
$query_Recordset1 = "SELECT auth_email FROM Authors WHERE Cancel = 'Cancel'";
$Recordset1 = mysql_query($query_Recordset1, $xxxxxx) or die(mysql_error());
$row_Recordset1 = mysql_fetch_assoc($Recordset1);
In the second db where they are also listed, (table and column names are identical) I want to update them because they cancelled. To select their records for updating, I want to take the first recordset, put it into an array, swap out the connStrings, then search using that array.
These also work.
$results = array();
do {
results[] = $row_Recordset1;
} while ($row_Recordset1 = mysql_fetch_assoc($Recordset1));
print_r($results);
gives me an array. Array ( [0] => Array ( [auth_email] => renault#autxxx.com ) [1] => Array ( [auth_email] => rinaldi#autxxx.com ) [2] => Array ( [auth_email] => hemingway#autxxx.com )) ...so I know it is finding the first set of data.
Here's the problem: The query of the second database looks for the author by auth_email if it is 'IN' the $results array, but it is not finding the authors in the 2nd database as I expected. Please note the different connString
require_once('ConnString/SecondAuth.php');
mysql_select_db($xxxxx, $xxxxxx);
$query_Recordset2 = "SELECT auth_email FROM Authors WHERE auth_email IN('$results')";
$Recordset2 = mysql_query($query_Recordset2, $xxxxxx) or die(mysql_error());
$row_Recordset2 = mysql_fetch_assoc($Recordset2);
The var_dump is 0 but I know that there are two records in there that should be found.
I've tried various combinations of IN like {$results}, but when I got to "'$results'", it was time to ask for help. I've checked all the available posts and none resolve my problem though I am now more familiar with the wild goose population.
I thought that since I swapped out the connection string, maybe $result was made null so I re-set it to the original connString and it still didn't find auth_email in $results in the same database where it certainly should have done.
Further, I've swapped out connStrings before with positive results, so... hmmm...
My goal, when working, is to echo the Recordset2 into a form with a do/while loop that will permit me to update their record in the 2nd db. Since the var_dump is 0, obviously this below isn't giving me a list of authors in the second table whose email addresses appear in the $results array, but I include it as example of what I want use to start the form in the page.
do {
$row_Recordset2['auth_email_addr '];
} while($row_Recordset2 = mysql_fetch_assoc($Recordset2));
As always, any pointer you can give are appreciated and correct answers are Accepted.
If you have a db user that has access to both databases and tables, just use a cross database query to do the update
UPDATE
mydb.Authors,
mydb2.Authors
SET
mydb.Authors.somefield = 'somevalue'
WHERE
mydb.Authors.auth_email = mydb2.Authors.auth_email AND
mydb2.Authors.Cancel= 'Cancel'
The IN clause excepts variables formated like this IN(var1,var2,var3)
You should use function to create a string, containing variables from this array.
//the simplest way to go
$string = '';
foreach($results as $r){
foreach($r as $r){
$string .= $r.",";
}
}
$string = substr($string,0,-1); //remove the ',' from the end of string
Its not tested, and obviously not the best way to go, but to show you the idea of your problem and how to handle it is this code quite relevant.
Now use $string instead of $results in query
hey everyone im new here as well as to php only been at it for about 2 months kinda learning as i go. what i need to get done right now is to take data from about 16 different tables in a data base and duplicate the tables. the table are for applicants and either have an application id in common or a family id in commmon the id's are just genereated hashes. what im doing right now is individually wquerying every table and then doing an insert using the data and just changing the application id and or family id. some tables are pretty big and im trying to figuere out an easier faster way to do this heres an example piece iv writen for one of my tables.
<?
//get family info based on application id
$queryC="SELECT Fam_Type, Fam_Title, Fam_SSNI20, Fam_SSNI20_Select, Fam_Name_First, Fam_Name_Middle, Fam_Name_Last, Fam_Name_Suffix, Fam_Gender, Fam_DOB, Fam_Disabled, Fam_Addy1, Fam_Addy2, Fam_City, Fam_State_Prov, Fam_Zip, Fam_Country, Fam_Home_Phone, Fam_Work_Phone, Fam_Work_Phone_Ext, Fam_Cell_Phone, Fam_Occupation, Fam_Employer, Fam_Primary_Res, Fam_Custody, Fam_Guard_Excuse, Fam_ChiDep_Ans, Fam_ReaVeh_Ans, InstructDone, SetDone, AppDone, HouDone, DepDone, AssDone, ReaDone, IncDone, ExpDone, QueDone, ApplicationDone, StatusDone, Fam_Init, Fam_Start_Date, Fam_End_Date, Fam_Agree, username, password, email, Fam_Letter, Exp_Educational, Fam_Tax, Scan_FileNames, Scan_Descriptions, Fam_Complete, referral, Fam_Holds, appealed, Appeal_Letter, Appeal_Viewed, taxDocuments
FROM familY
WHERE familyID='$famid' AND applicationID='$appid'";
$resultC = mysql_db_query($aidDB, $queryC, $connection); echo $queryC;
while($rC=mysql_fetch_array($resultC)){
$Fam_Type="$rC['0']";
$Fam_Title="$rC['1']";
$Fam_SSNI20="$rC['2']";
$Fam_SSNI20_Select="$rC['3']";
$Fam_Name_First="$rC['4']";
$Fam_Name_Middle="$rC['5']";
$Fam_Name_Last="$rC['6']";
$Fam_Name_Suffix ="$rC['7']";
$Fam_Gender="$rC['8']";
$Fam_DOB="$rC['9']";
$Fam_Disabled="$rC['10']";
$Fam_Addy1 ="$rC['11']";
$Fam_Addy2 ="$rC['12']";
$Fam_City="$rC['13']";
$Fam_State_Prov="$rC['14']";
$Fam_Zip="$rC['15']";
$Fam_Country="$rC['16']";
$Fam_Home_Phone ="$rC['17']";
$Fam_Work_Phone ="$rC['18']";
$Fam_Work_Phone_Ext="$rC['19']";
$Fam_Cell_Phone ="$rC['20']";
$Fam_Occupation ="$rC['21']";
$Fam_Employer="$rC['22']";
$Fam_Primary_Res ="$rC['23']";
$Fam_Custody="$rC['24']";
$Fam_Guard_Excuse ="$rC['25']";
$Fam_ChiDep_Ans ="$rC['26']";
$Fam_ReaVeh_Ans="$rC['27']";
$InstructDone ="$rC['28']";
$SetDone ="$rC['29']";
$AppDone ="$rC['30']";
$HouDone ="$rC['31']";
$DepDone ="$rC['32']";
$AssDone="$rC['33']";
$ReaDone ="$rC['34']";
$IncDone ="$rC['35']";
$ExpDone ="$rC['36']";
$QueDone="$rC['37']";
$ApplicationDone ="$rC['38']";
$StatusDone ="$rC['39']";
$Fam_Init="$rC['40']";
$Fam_Start_Date ="$rC['41']";
$Fam_End_Date ="$rC['42']";
$Fam_Agree ="$rC['43']";
$username ="$rC['44']";
$password ="$rC['45']";
$email ="$rC['46']";
$Fam_Letter="$rC['47']";
$Exp_Educational ="$rC['48']";
$Fam_Tax ="$rC['49']";
$Scan_FileNames="$rC['50']";
$Scan_Descriptions ="$rC['51']";
$Fam_Complete ="$rC['52']";
$referral="$rC[''53]";
$Fam_Holds="$rC['54']";
$appealed="$rC['55']";
$Appeal_Letter="$rC['56']";
$Appeal_Viewed="$rC['57']";
$taxDocuments="$rC['58']";
//insert into family with new applicationid
$queryC2="INSERT INTO family (familyID, applicationID, Fam_Type, Fam_Title, Fam_SSNI20, Fam_SSNI20_Select, Fam_Name_First, Fam_Name_Middle, Fam_Name_Last, Fam_Name_Suffix, Fam_Gender, Fam_DOB, Fam_Disabled, Fam_Addy1, Fam_Addy2, Fam_City, Fam_State_Prov, Fam_Zip, Fam_Country, Fam_Home_Phone, Fam_Work_Phone, Fam_Work_Phone_Ext, Fam_Cell_Phone, Fam_Occupation, Fam_Employer, Fam_Primary_Res, Fam_Custody, Fam_Guard_Excuse, Fam_ChiDep_Ans, Fam_ReaVeh_Ans, InstructDone, SetDone, AppDone, HouDone, DepDone, AssDone, ReaDone, IncDone, ExpDone, QueDone, ApplicationDone, StatusDone, Fam_Init, Fam_Start_Date, Fam_End_Date, Fam_Agree, username, password, email, Fam_Letter, Exp_Educational, Fam_Tax, Scan_FileNames, Scan_Descriptions, Fam_Complete, referral, Fam_Holds, appealed, Appeal_Letter, Appeal_Viewed, taxDocuments )
VALUES
(
'$newfam1id,'
'$newappid,'
'$Fam_Type,'
'$Fam_Title,'
'$Fam_SSNI20,'
'$Fam_SSNI20_Select,'
'$Fam_Name_First,'
'$Fam_Name_Middle, '
'$Fam_Name_Last,'
'$Fam_Name_Suffix,'
'$Fam_Gender,'
'$Fam_DOB,'
'$Fam_Disabled,'
'$am_Addy1,'
'$Fam_Addy2,'
'$Fam_City,'
'$Fam_State_Prov,'
'$Fam_Zip,'
'$Fam_Country,'
'$Fam_Home_Phone,'
'$Fam_Work_Phone, '
'$Fam_Work_Phone_Ext,'
'$Fam_Cell_Phone,'
'$Fam_Occupation,'
'$Fam_Employer,'
'$Primary_Res,'
'$Fam_Custody,'
'$Fam_Guard_Excuse,'
'$Fam_ChiDep_Ans,'
'$Fam_ReaVeh_Ans,'
'$InstructDone,'
'$SetDone,'
'$AppDone,'
'$HouDone,'
'$DepDone,'
'$AssDone,'
'$ReaDone,'
'$IncDone,'
'$ExpDone,'
'$QueDone,'
'$ApplicationDone,'
'$StatusDone,'
'$Fam_Init,'
'$Fam_Start_Date,'
'$Fam_End_Date,'
'$Fam_Agree,'
'$username,'
'$password,'
'$email,'
'$Fam_Letter,'
'$Exp_Educational,'
'$Fam_Tax,'
'$Scan_FileNames,'
'$Scan_Descriptions,'
'$Fam_Complete,'
'$referral,'
'$Fam_Holds,'
'$appealed,'
'$Appeal_Letter,'
'$Appeal_Viewed,'
'$taxDocuments'
)"; echo $queryC2;
}
?>
you do not need to loop all the rows.
use this:
Insert into new_table select * from old_table where {your criteria here}
mysql has INSERT into table (fields,list) SELECT fields,list FROM another_table syntax
You can reduce the amount of PHP code on the SELECT side of things by using mysql_fetch_assoc() instead of array, especially since you're then just reassigning the returned array chunks to individual variables:
$query = "SELECT Fam_Type, Fam_Title, Fam_SSNI20, Fam_SSNI20_Select etc... etc...";
$resultC = mysql_db_query($aidDB, $queryC, $connection); echo $queryC;
while($rC = mysql_fetch_assoc($resultC)) {
...
}
At this point you end up with associated array which you can get at the individual values as:
echo "Fam_Type is " . $rc['Fam_Type'];
echo "Fam_Title is " . $rc['Fam_Title'];
which saves you that long huge blob of variable assignments. Of course, if any of the fields in your query would map internally to the same name (say, you're doing a join and are retrieving two different 'id' fields from two different tables), then you'd need to alias them to different names so they come out distinctly in the array, but that's a simple mod to the query:
SELECT table1.id AS table1_id, table2.id AS table2_id ...
which would leave to:
$result['table1_id'] = ...
As a side node, you should always check to see if the query succeeded. You blindly assume it worked and try to retrieve data. But if the query fails, the mysql functions return FALSE, which would not be a valid result statement and break your fetch attempt. At bare minimum, add some basic error checking
$resultC = mysql_db_query(...) or die("MySQL error: " . mysql_error());
which will spit out the error message and explain why the query failed, instead of then failing with "... is not a valid statement handle" later on. As well, mysql_db_query() is deprecated as of PHP 5.3, and will vanish in some future PHP version. May want to switch to the regular mysql_query() instead.
you can simply do:
INSERT INTO family ( appliction_id, all_the_other_fields )
SELECT 'your_new_app_id', all_the_other_fields
FROM familY
WHERE familyID='$famid' AND applicationID='$appid'
let's hope your $famid and $appid variables are escaped, shall we?
I am writing my own PDO wrapper to make my life easier and a fair amount safer.
A standard query looks like:
$user = $db->select('users')
->eq('twitter_id', $twitter_id)
->limit(1)
->prepare()
->exec();
Generates this query:
SELECT * FROM users WHERE twitter_id = :twitter_id LIMIT 1
This works perfectly fine as I, currently, want it. Where I am running into a problem is when I have a query to return multiple rows.
My apps stores some dynamic settings that I want to grab and use in one pass and I can do that by running a query like:
$share_datas = $db->select('settings', 'setting, value')
->prepare()
->exec();
Which generates:
SELECT setting, value FROM settings
Which returns:
Array
(
[0] => Array
(
[setting] => since_id
[value] => 17124357332
)
[1] => Array
(
[setting] => last_dm
[value] => 1271237111
)
)
The function prepare() puts the pieces together for the query and the function exec() binds the params and returns the array.
function exec()
{
// echo 'vars: <pre>'.print_r($this->sql_vars, true).'</pre>';
$stmt = $this->dbh->prepare($this->sql_last_query);
foreach($this->sql_vars as $key => $val)
{
if('date_time' === $key) continue;
$bind = $stmt->bindValue($key, $val);
}
$stmt->execute();
$this->sql_vars = array();
return $stmt->fetchAll(PDO::FETCH_ASSOC);
}
Now to the question: Is there a way that I can change exec() or the query itself so that it can return an array that returns like below and avoids any additional loops?
Array
(
[since_id] => 17124357332
[last_dm] => 1271237111
)
No problem with some simple array functions.
$in = $db->exec();
$out = array();
foreach( $in as $row )
$out[ $row['setting'] ] = $row['value'];
If you need a more general function, you'll have to describe the transformation clearer.
The answer is likely going to be either:
Creating multiple versions of your exec method with different return behavior, or
Having exec simply perform the execution and store the statement handle, then have fetching the data be a separate method.
I've found the following convenience methods handy, in addition to your current array of hashes:
Query "one": The first column in the first row as a scalar (for things like SELECT COUNT(*))
Query "list": The first column of all rows as an indexed array (for things like SELECT id FROM ...))
Query "pairs": The first two columns of all rows as a hash (for your current problem)
Query "insert id": The last generated row id as a scalar (autoincrement in MySQL, sequence in Postgres, etc)
These are all occasionally convenient things that PDO (and most other database adapters) simply don't have built-in flags to handle.