I'm probably overlooking a fairly simple way of doing this; perhaps someone has an idea of how to make this easy with limited looping and without an excessively long query. Let's say I have a MySQL table with data like this: (There's 12 months, and could be maybe 10 different possible grades). I'll query out just the results for a given user_id and year.
+----+---------+------+-------+-------+-------+
| id | user_id | year | month | grade | value |
+----+---------+------+-------+-------+-------+
| 1 | 1 | 2021 | Jan | A | 95 |
+----+---------+------+-------+-------+-------+
| 2 | 2 | 2021 | Jan | D | 75 |
+----+---------+------+-------+-------+-------+
| 3 | 2 | 2021 | Feb | F | 45 |
+----+---------+------+-------+-------+-------+
I want to be able to query the data and put it into a multi-dimensional associative PHP array.
Essentially, so I can access the data like this:
echo $month_value['Jan']['D']; // Should give me 75
echo $month_value['Feb']['F']; // Should give me 45
Figured out a simple method that works for me:
$sql_retrieve = $con->prepare("SELECT month, grade, value
FROM table
WHERE user_id = ? AND year = ?;");
$bind_process = $sql_retrieve->bind_param('ii',$user_id,$year);
$sql_retrieve->execute();
$result = $sql_retrieve->get_result();
$month_values = []; // initialize array
if($result->num_rows > 0 ){ // If there are results
while($row=$result->fetch_assoc()){
$month_values[$row["month"]][$row["grade"]] = $row["value"]; // add to array
} // end while
} // end of if num_rows > 0
print_r($month_values); // Example
echo 'Value: '.$month_values['Jan']['D'];
This then provides the MySQL results into a multi-dimensional associative PHP array, so they can be referenced as such.
Related
SOLUTION: Make sure you don't 'use up' any $responses->fetch_assoc()s before the while loop.
I performed mysqli_fetch_array($responses);.
In php I have this sql query (simplified for your convenience, but the problem remains)
$sql = "SELECT id, content FROM responses ORDER BY RAND()";
$responses = $conn->query($sql);
where the responses table looks like this:
+----+----------+--------+------+
| id | content | userId | part |
+----+----------+--------+------+
| 4 | peewee | 31 | 1 |
| 5 | tallinn | 31 | 1 |
| 6 | dewey | 31 | 1 |
| 7 | stanford | 31 | 1 |
+----+----------+--------+------+
That doesn't format properly so all you need to know is that the id and content rows are different for each entry while the rest is the same for each.
The problem is, when I do a while loop on $responses like so:
while ($row = $responses->fetch_assoc()) {
$responseId = $row["id"];
$content = $row["content"];
echo " id: ".$responseId;
echo " content: ".$content;
}
I always get 1 record fewer than there are. In this case, since there are 4 rows, I would only see 3 echoed. However, it is not always the same 3, nor are they in the same order. If I remove the ORDER BY RAND() clause, then it is always the first record which is left out.
Thanks in advance
Cheers
I'd like to fetch data from my 2 sql database and do some math and post the result in database
let's say my table1 is like this
+---+---+----------------------------+
| A | B | C |
+---+---+----------------------------+
| 2 | 9 | result from A*B*D*E in php |
| 1 | 8 | result from A*B*D*E in php |
| 4 | 7 | result from A*B*D*E in php |
| 3 | 6 | result from A*B*D*E in php |
| 6 | 5 | result from A*B*D*E in php |
| 6 | 5 | result from A*B*D*E in php |
| 5 | 4 | result from A*B*D*E in php |
+---+---+----------------------------+
and my table2 is like this
+---+----+
| D | E |
+---+----+
| 1 | 9 |
| 2 | 7 |
| 3 | 8 |
| 4 | 6 |
| 5 | 5 |
| 6 | 3 |
| 7 | 2 |
+---+----+
so far what i've done
// database connection
include_once("config.php");
// Query
$query = mysqli_query($conn, "SELECT * FROM table1");
$query2 = mysqli_query($conn, "SELECT * FROM table2");
//Source1
while($user_data1 = mysqli_fetch_array($query))
{
$A[] = $user_data1['A'];
$B[] = $user_data1['B'];
}
//Source2
while($user_data2 = mysqli_fetch_array($query2))
{
$D[] = $user_data2['D'];
$E[] = $user_data2['E'];
}
foreach (array_combine($A, $B) as $ValueA=> $ValueB)
{
foreach (array_combine($D, $E) as $ValueD=> $ValueE)
{
$result1 = $ValueA*$ValueB*ValueD*ValueE;
$val = 0.123;
$result2[] = $result1*$val;
}
$final result = min($result2);
echo round($final result, 2);
unset($result2);
}
I haven't inserted the database yet
still echoing for debug if the math is correct
somehow this code found some bug
for example using my database the final result only echo/showing 6 math result
because in table1 row 5 and 6 has same data
btw of course in my table1 and 2 has primary key
To change C in this case, you don't even need PHP. To UPDATE a value in MySQL with multiple tables just add them with a , when selecting the tables, like this:
UPDATE table1,table2 SET C = table1.A * table1.B * table2.D * table2.E WHERE C IS NULL;
Executing this code once will update all rows so that C = A*B*D*E as wanted where C is not yet set or NULL. If you want to update all rows you can just remove the WHERE condition
Note: Sometimes (at least for me) SQL will give a warning when having no WHERE condition in the SQL query. To bypass this just add WHERE 1=1 at the end.
Just for my understanding: you want to calculate a value for your calculation you need some data from table 1 that is clear, but also from table2 But which one? I guess you want to use the data from the same row ( so row 1 from table1 and row 1 from table2, row 2 from table 1 and row 2 from table2 ) right? Now you have an problem because when you make a select * from table You do not know in which order they give back from your database. Most time it may be the same order as you have input them, but there is no garantie. You have sayed you have an primary key on each table, how have you defined them? I guess you may have a id column, so you can join your table on that id?
I've been trying to solve this issue I'm currently having. We have a table with id, productid, userid, count and downloaddate. Something like below to understand the structure and what the results look like.
+----+-----------+--------+-------+---------------+
| id | productid | userid | count | downloaddate |
+----+-----------+--------+-------+---------------+
| 1 | 9 | 231 | 2 | October 2017 |
| 2 | 8 | 230 | 1 | October 2017 |
| 3 | 9 | 287 | 1 | October 2017 |
| 4 | 9 | 200 | 2 | November 2017 |
+----+-----------+--------+-------+---------------+
So what I want to loop is to get all the productid and return the total number of count for the given month which is recorded in the downloaddate column.
To return this:
+------------+-------+---------------+
| productid | count | downloaddate |
+------------+-------+---------------+
| 9 | 3 | October 2017 |
| 8 | 1 | October 2017 |
| 9 | 2 | November 2017 |
+------------+-------+---------------+
Is it possible to do this? I've tried this but it's returning the total count for the productid
$sum = array();
$emparray = array();
foreach ($downloads as $download){
$emparray[] = $download;
}
foreach ($emparray as $downloaded){
if (!isset($sum[$downloaded->id])) {
$sum[$downloaded->id]['count'] = $downloaded->count;
$sum[$downloaded->id]['downloaddate'] = $downloaded->downloaddate;
} else {
$sum[$downloaded->id]['count'] += $downloaded->count;
$sum[$downloaded->id]['downloaddate'] = $downloaded->downloaddate;
}
}
Any help will be appreciated!
EDIT
This is my sql query:
$downloads = $wpdb->get_results(
"
SELECT ast.*, dl.userid, dl.count, dl.downloaddate
FROM $lead_table as ast
JOIN $table_downloads as dl ON (dl.productid = ast.id)
"
);
You can get the result by one query grouping by productid and downloaddate (I hope that October2017 is a typo in the question)
SELECT productid, sum(count) as count, downloaddate
FROM your_table
GROUP BY productid, downloaddate
update. with your query it seems to be
SELECT ast.*, dl.userid, sum(dl.count) as count, dl.downloaddate
FROM $lead_table as ast
JOIN $table_downloads as dl
ON (dl.productid = ast.id)
GROUP BY dl.userid, dl.downloaddate
i think you should edit your sql Query into this :
SELECT productid, sum(count) as count, downloaddate FROM your_table GROUP BY downloaddate
You have to be able to tell which month is given in the downloaddate (can you build a timestamp ? Or something else that tells you that "October2017" is the same that "October 2017".
Once you got that, you "just" have to store your "sum" in a 2D array with something like that:
$sum = array();
foreach ($downloads as $download) {
// dateToTimeStamp: custom function who gives you the same number for October2017 or October 2017
$timestamp = dateToTimeStamp($downloaded->downloaddate);
if (!isset($sum[$timestamp])) {
$sum[$timestamp] = [];
}
if (!isset($sum[$timestamp][$downloaded->id])) {
$sum[$timestamp][$downloaded->id]['count'] = $downloaded->count;
$sum[$timestamp][$downloaded->id]['downloaddate'] = $downloaded->downloaddate;
continue 1;
}
$sum[$timestamp][$downloaded->id]['count'] += $downloaded->count;
$sum[$timestamp][$downloaded->id]['downloaddate'] = $downloaded->downloaddate;
}
you can easily use this query and extract the data from php and use it there
select productid,sum(count),downloaddate from tablename group by productid,downloaddate
i'm using mysql to store Kwh usage of my home. I get a fault rarely and get a 0 value to get stored. When i extract the values from my table i don't want to get that 0s but the last valid value before.
SELECT unix_timestamp(dataora) as time, kwhg
FROM misure
WHERE dataora BETWEEN '2013-10-08 00:00:00.000' AND '$data_scelta 23:59:59.997'
GROUP BY date(dataora),hour(dataora)
I used the above code to get the below table:
+-------+-----------+
| time | kwhg |
+-------+-----------+
| 9 | 2 |
| 10 | 3 |
| 11 | 0 |
| 12 | 4 |
| 13 | 0 |
+-------+-----------+`
I want to obtain
+--------+----------+
| time | kwhg |
+-------+-----------+
| 9 | 2 |
| 10 | 3 |
| 11 | 3 |
| 12 | 4 |
| 13 | 4 |
+-------+-----------+`
and remove the zero with the previus value.
Any tricks to do that?
You can use MySQL user-defined variables to return either the current row's value of kwhg if it's greater than zero, or else the variable defined on the previous row.
SELECT unix_timestamp(dataora) as time, #kwhg := IF(kwhg>0, kwhg, #kwhg) AS kwhg
FROM misure
WHERE dataora BETWEEN '2013-10-08 00:00:00.000' AND '$data_scelta 23:59:59.997'
GROUP BY date(dataora),hour(dataora)
Like #OddEssay's answer, this can't come up with a nonzero value if the first entry is zero. In that case, it will return whatever the current value of #kwhg is, which is probably NULL unless you've run the query before in the current session.
If it's a small result set, you could simply loop over it and created a fixed dataset with something like:
$fixedResults = array();
$lastGoodReading = 0;
foreach($results as $row){
if($row['kwhg']){
$fixedResults[$row['time']] = $row['kwhg'];
$lastGoodReading = $row['kwhg'];
} else {
$fixedResults[$row['time']] = $lastGoodReading;
}
}
Which will work if there is multiple failed readings in a row, but will still give zero if the first result fails.
You might also want to do something a bit more advanced, like checking both the previous result, and the next result and take an average of the two.
in mysql
UPDATE mytable
SET kwhg = (#n := COALESCE(number, #n))
ORDER BY time;
#n is a MySQL user variable
Started learning PHP and MySQL yesterday and have managed to create two tables, insert rows and then display that data on a web page using various different groupings. Now I need to do a calculation based on data in the two tables and write the result back to one of the tables.
I'm trying to figure out how to perform an equation for a row with a date in table A using a range of values associated with a range of dates in table B. The two dates are in the format YYYY-MM-DD, but the days mostly do not match, so I need match on the month.
Here's the two tables I have:
Table A (user)
+----+----------+------------+-------------+
| id | username | start-date | bench-value |
+----+----------+------------+-------------+
| 1 | tim | 2010-03-04 | |
+----+----------+------------+-------------+
| 2 | jim | 2010-05-30 | |
+----+----------+------------+-------------+
| 3 | fred | 2010-06-12 | |
+----+----------+------------+-------------+
| 4 | sam | 2010-08-16 | |
+----+----------+------------+-------------+
| 5 | jane | 2010-10-21 | |
+----+----------+------------+-------------+
| 6 | ella | 2010-10-21 | |
+----+----------+------------+-------------+
| 7 | bob | 2011-01-24 | |
+----+----------+------------+-------------+
Table B (benchmark)
+----+------------+---------+
| id | start-date | value |
+----+------------+---------+
| 1 | 2010-01-31 | 1173.19 |
+----+------------+---------+
| 2 | 2010-02-28 | 1199.85 |
+----+------------+---------+
| 3 | 2010-03-31 | 1264.91 |
+----+------------+---------+
| 4 | 2010-04-30 | 1263.43 |
+----+------------+---------+
| 5 | 2010-05-31 | 1211.36 |
+----+------------+---------+
| 6 | 2010-06-30 | 1187.32 |
+----+------------+---------+
| 7 | 2010-07-31 | 1218.30 |
+----+------------+---------+
| 8 | 2010-08-31 | 1207.96 |
+----+------------+---------+
| 9 | 2010-09-30 | 1272.12 |
+----+------------+---------+
| 10 | 2010-10-31 | 1280.27 |
+----+------------+---------+
| 11 | 2010-11-30 | 1275.60 |
+----+------------+---------+
| 12 | 2010-12-31 | 1346.45 |
+----+------------+---------+
| 13 | 2011-01-31 | 1337.07 |
+----+------------+---------+
| 14 | 2011-02-28 | 1338.37 |
+----+------------+---------+
| 15 | 2011-03-31 | 1349.14 |
+----+------------+---------+
And here's an example of what I'm trying to achieve:
tim's current bench value today = the sum of: (first(benchmark.value)/latest(benchmark.value))for every month from the first to the latest month inclusive
First date = 2010-03 which is id 3 = 1264.91
Latest date = 2011-03 which is id 15 = 1349.14 (this is always the last row as I am trying to calculate on "today" and nothing in the future)
1/(first/latest) =1/(1264.91/1349.14) = 1.0666 [this is bench.id=3]
...now iterate...
1/(next/latest) =1/(1263.43/1349.14) = 1.0678 [bench.id=4]
1/(next/latest) =1/(1211.36/1349.14) = 1.1137 [bench.id=5]
1/(next/latest) =1/(1187.32/1349.14) = 1.1363 [bench.id=6]
1/(next/latest) =1/(1218.30/1349.14) = 1.1074 [bench.id=7]
1/(next/latest) =1/(1207.96/1349.14) = 1.1169 [bench.id=8]
1/(next/latest) =1/(1272.12/1349.14) = 1.0605 [bench.id=9]
1/(next/latest) =1/(1280.27/1349.14) = 1.0538 [bench.id=10]
1/(next/latest) =1/(1275.60/1349.14) = 1.0577 [bench.id=11]
1/(next/latest) =1/(1346.45/1349.14) = 1.0020 [bench.id=12]
1/(next/latest) =1/(1337.07/1349.14) = 1.0090 [bench.id=13]
1/(next/latest) =1/(1338.37/1349.14) = 1.0080 [bench.id=14]
...and finish up...
1/(current/latest) =1/(1349.14/1349.14) = 1.0000 [bench.id=15]
Total = 13.7997 = 1.0666 + 1.0678 + 1.1137 + 1.1363 + 1.1074 + 1.1169 + 1.0605 + 1.0538 + 1.0577 + 1.002 + 1.009 + 1.008 + 1
So I would then want to write that result back to Table A, giving me:
Table A (user)
+----+----------+------------+-------------+
| id | username | start-date | bench-value |
+----+----------+------------+-------------+
| 1 | tim | 2010-03-04 | 13.7997 |
+----+----------+------------+-------------+
As this is an iterative process it would be a much shorter calculation for a user like 'bob' who started in 2011-01.
I would also like to be able to do this every 4 months to produce termly stats so that someone like user tim would be calculated like this (the initial search to find the first date would need to take into account over a 4 month period):
1/(first/latest) = 2010-03 = 1/(1264.91/1349.14) = 1.0666
1/(next/latest) = 2010-07 = 1/(1218.30/1349.14) = 1.1074
1/(next/latest) = 2010-11 = 1/(1275.60/1349.14) = 1.0577
1/(current/latest) = 2011-03 = 1/(1349.14/1349.14) = 1.0000
Total = 1.0666 + 1.1074 + 1.0577 + 1 = 4.2317
That major issues I'm having are two fold:
1. how to use the user.start-date value for each user to pick the first(benchmark.value) based ont he year and the month (day is unimportant).
2. how to iteratively calculate the formula up to and including the latest value in the bench table - at the end of april, a new row with id=16 would be added and if this were run then the April value would become the last value used in the calculation.
As I'm learning SQL And PHP right now I'm not sure which parts of this process should be done in SQL and which in PHP.
Any and all help would be greatly appreciated as I'm determined to figure this out.
That major issues I'm having are two fold:
how to use the user.start-date value
for each user to pick the
first(benchmark.value) based on the
year and the month (day is
unimportant).
how to iteratively calculate the
formula up to and including the
latest value in the bench table - at
the end of april, a new row with
id=16 would be added and if this
were run then the April value would
become the last value used in the
calculation.
As I'm learning SQL And PHP right now I'm not sure which parts of this process should be done in SQL and which in PHP.
Any and all help would be greatly appreciated as I'm determined to figure this out.
Just for reference, I've been reading:
http://dev.mysql.com/doc/refman/5.1/en/date-and-time-functions.html
http://www.databasejournal.com/features/mssql/article.php/10894_2191631_3/Working-with-SQL-Server-DateTime-Variables.htm
There were more but it won't let me post the other links yet...
There's almost too much info out there, so some guided advice would be realy appreciated. Thanks again.
I wouldn't include the column bench-value in table A. This value will be constantly changing, so it would be better to create a View that would calculate the latest User bench-value or create a stored procedure that takes a User as a parameter and then returns the bench-value
There also needs to be a link/key between the two tables, right now there is no way to tell which user is related to which benchmark
Wow, what a well asked question. Sadly my reply maybe a lot shorter.
What I think you're looking for is:
bob's current bench value today = the
sum of:
first(benchmark.value)/latest(benchmark.value)
First date = 2011-01 which is id 13 =
1337.07 Latest date = 2011-03 which is id 15 = 1349.14
select username, start_date, tmp.value/tmp2.value as new_mark from tablea
join (select id,value from tableb having id=min(id) group by id) as tmp
on tablea.id=tmp.id
join (select id,value from tableb having id=max(id) group by id) as tmp2
on tablea.id=tmp2.id
That seems ugly but should work.