Looping through data from multiple tables PHP/Mysql - php

HI all,
I am trying to figure out how to put this into words even, but I am wanting to know how to format the output from each table separately in a "multiple table" mysql query. The output from the table1 "wall" is formatted within a while loop, but the content from table2 "actions" is already formatted(as 1 line of text with links) before it is inserted into the table(column action_body), so inside the loop I would only be outputting the action_date and action_body columns from the actions table.
I am probably not using the correct sql method(if Im doing anything right at all, that is) for the results I need, so feel free to correct my novice example, or suggest a new way to approach this.
Query:
$query = "SELECT wall.wall_id, wall.wall_owner_id, wall.wall_user_id,
wall.wall_post_date, wall.wall_post_content, actions.action_id,
actions.action_date, actions.action_user_id, actions.action_title,
actions.action_body FROM wall, actions
ORDER BY wall.wall_post_date, actions.action_date DESC";
$result = mysql_query($query);
while( $rows = mysql_fetch_assoc($result) {
// What to put here
}
Any help is appreciated, thanks, Lea

Update after comments
SELECT w.* FROM (
(SELECT
'w' as type,
wall_id as id,
wall_owner_id as owner_id,
wall_user_id as user_id,
wall_post_date as post_date,
NULL as title,
wall_post_content as content
FROM wall
WHERE wall_owner_id = x # user id of owner
)
UNION
(SELECT
'a' as type,
action_id as id,
action_user_id as owner_id,
NULL as user_id,
action_post_date as post_date,
action_title as title,
action_body as content
FROM actions
WHERE action_user_id = x # user id of owner
)
) w
ORDER BY w.post_date DESC

Because you don't JOIN on a specific field, you're gonna get every row-row combination of the two tables, which is a whole lot more data than you probably want.
You'd be better of by doing 2 queries, one for each table. While looping through the result of each table, you can collect the data you want in one array, with the field you want to sort it by as array key.
Then you sort the array, and loop through it to print it out.

Related

PHP CI sql query syntax

I need some help with a query as I don't seem to get my head around it.
First table vacancies:
vac_id
vac_title
vac_location
vac_description
is_deleted
status
Second table vacancies_labels:
vac_id
Label_id
Now I would like to get an output containing all vacancies within a certain location but they also cannot contain the label_id '10' nonetheless of the location.
SELECT `v`.*
FROM `vacancies` AS `v`
LEFT JOIN `vacancies_labels` as `vl` ON `v`.`vacancy_id` = `bl`.`vacancy_id`
WHERE `v`.`vac_location` = 'russia'
AND `v`.`is_deleted` != 1
AND `v`.`status` = 1
AND `vl`.`label_id` NOT IN ('10')
GROUP BY `v`.`vacancy_id`
This results only in the vacancies that have a record in the vacancies_labels table that are not 10. It leaves out however all vacancies that have no records at all in the vacancies_labels table but fit within the location range.
What am I missing here?
Thx!
Using a LEFT JOIN, if the record is not found, then the values will return null. But in your WHERE clause, you have
AND `vl`.`label_id` NOT IN ('10')
as NOT IN doesn't consider nulls you have to do something like...
AND ( `vl`.`label_id` NOT IN ('10') OR `vl`.`label_id` IS NULL)

Convert MySQL Query into JSON using PHP

I have a question about using a MySQL Query to convert my data into a JSON Object. The Query I have is converting to a JSON Object, but it is not working the way I would like.
I have multiple tables in my database that I would like to graph on a chart using the date as the X axis and the values as the Y axis. I am currently joining the tables by date. However, some tables may have multiple submissions per day while others may not have any. Currently, the Query I have is only showing results for dates that data was submitted to all 4 tables.
I would also like to graph the information on a scale of 0-10. Three of the 4 tables only have values from 0-10 so I am taking the average of each value per day. The nutrition table, which holds nf_sugars and nf_total_carbohydrates has larger numbers that I will be using normalization to convert them into a 0-10 scale. For now, I am just attempting to get the SUM per day and will complete the rest of the calculation after this part is working. However, the query I am currently running is giving me results that are much higher than the SUM of the actual numbers in my database.
Any help would be greatly appreciated! Here is the PHP I am currently using to create the JSON Object. As a side note, I did successfully connect to my database, I just did not include that here.
$myquery = "SELECT track_ticseverity.date,
AVG(track_ticseverity.ticnum) as average_ticnum,
track_fatigue.date,
AVG(track_fatigue.fatiguenum) as average_fatiguenum,
track_stress.date,
AVG(track_stress.stressnum) as average_stressnum,
track_nutrition.date,
((SUM(track_nutrition.nf_sugars) ) ) as sum_nf_sugars,
((SUM(track_nutrition.nf_total_carbohydrate) ) ) as sum_nf_total_carbohydrate
FROM track_ticseverity
INNER JOIN track_fatigue
ON track_ticseverity.date=track_fatigue.date
INNER JOIN track_stress
ON track_fatigue.date=track_stress.date
INNER JOIN track_nutrition
ON track_stress.date=track_nutrition.date
WHERE track_ticseverity.user_id=1
AND track_fatigue.user_id=1
AND track_stress.user_id=1
AND track_nutrition.user_id=1
GROUP BY track_ticseverity.date";
$query = mysqli_query($conn, $myquery);
if ( ! $query ) {
echo mysqli_error(s);
die;
}
$data = array();
for ($x = 0; $x < mysqli_num_rows($query); $x++) {
$data[] = mysqli_fetch_assoc($query);
}
echo json_encode($data);
mysqli_close($conn);
EDIT - The Query is successfully returning a JSON object. My issue is that the query I wrote does not output the data in the correct way. I need the query to select information from multiple tables, some with multiple submission per day and others with only one or no submissions.
EDIT2 - I am thinking another way to handle this is to combine multiple SELECT statements into a single JSON Object, but I am not sure how to do this.
The sum is larger than expected because of the joins. Imagine that a certain date
occurs in one track_nutrition record and two track_fatigue records, then the join
will make that the data from the first table is once combined with the first track_fatigue
record, and then again with the second record. Thus the same nf_sugars
value will be counted twice in the sum. This behaviour will also affect the averages.
You should therefore first perform the aggregations, and only then perform the joins.
Secondly, to ensure you catch all data, even if for a certain date not all tables have
values, you should use full outer joins. This will guarantee that each record in each table
will find its way in the result. Now, MySQL does not support such full outer joins, so
I use an extra sub-select to select all different dates from the 4 tables and then
"left join" them with the other aggregated data:
SELECT dates.date,
IFNULL(average_ticnum_n, 0) as average_ticnum
IFNULL(average_fatiguenum_n, 0) as average_fatiguenum
IFNULL(average_stressnum_n, 0) as average_stressnum
IFNULL(sum_nf_sugars_n, 0) as sum_nf_sugars
IFNULL(sum_nf_total_carbohydrate_n, 0) as sum_nf_total_carbohydrate
FROM (
SELECT DISTINCT user_id,
date
FROM (
SELECT user_id,
date
FROM track_ticseverity
UNION
SELECT user_id,
date
FROM track_fatigue
UNION
SELECT user_id,
date
FROM track_stress
UNION
SELECT user_id,
date
FROM track_nutrition
) as combined
) as dates
LEFT JOIN (
SELECT user_id,
date,
AVG(ticnum) as average_ticnum_n
FROM track_ticseverity
GROUP BY user_id,
date) as grp_ticseverity
ON dates.date = grp_ticseverity.date
AND dates.user_id = grp_ticseverity.user_id
LEFT JOIN (
SELECT user_id,
date,
AVG(fatiguenum) as average_fatiguenum_n
FROM track_fatigue
GROUP BY user_id,
date) as grp_fatigue
ON dates.date = grp_fatigue.date
AND dates.user_id = grp_fatigue.user_id
LEFT JOIN (
SELECT user_id,
date,
AVG(stressnum) as average_stressnum_n
FROM track_stress
GROUP BY user_id,
date) as grp_stress
ON dates.date = grp_stress.date
AND dates.user_id = grp_stress.user_id
LEFT JOIN (
SELECT user_id,
date,
SUM(nf_sugars) as sum_nf_sugars_n,
SUM(nf_total_carbohydrate) as sum_nf_total_carbohydrate_n
FROM track_nutrition
GROUP BY user_id,
date) as grp_nutrition
ON dates.date = grp_nutrition.date
AND dates.user_id = grp_nutrition.user_id
WHERE dates.user_id = 1
ORDER BY dates.date;
Note that you will get 0 values in some of the columns when there is no data for that
particular date. If you prefer to get NULL instead, remove the Nvl() from those columns
in the query above.
Then, to normalize all data on a 0 - 10 scale, you could look at the maximum
found for each type of value and use that for a conversion, or if you know beforehand
what the ranges are per type, then it is probably better to use that information, and
maybe code that in the SQL as well.
However, it always looks a bit odd to have values combined in a graph that actually use
different scales. One might easily jump to wrong conclusions with such graphs.
I will prefer to use this way (assuming all other things are working fine e.g query is working fine)
$query = mysqli_query($conn, $myquery);
if ( ! $query ) {
echo mysqli_error($conn); //You need to put $conn here to display error.
die;
}
$data = array();
while($row = mysqli_fetch_assoc($query)) {
$data[] = $row;
}
echo json_encode($data);
mysqli_close($conn);
if you are using PDO (PHP Data Objects) for database operations; then following code can be used to create the JSON from PDO.
$array = $pdo->query("SELECT * FROM employee")->fetchAll(PDO::FETCH_ASSOC);
echo json_encode($array);
For Multiple Select we need to try it like that way :
$array = $pdo->query("SELECT 1; SELECT 2;");
$array->nextRowset();
var_dump( $array->fetchAll(PDO::FETCH_ASSOC) );

How to count if value of a variable is repeated?

I am learning how to work with MySQL, and at the moment I succeed to show data from my table, using:
while($objResult2 = mysqli_fetch_assoc($objQuery_product)) {
Results are shown by using this variable $objResult2["id_product"]; this way i can take from DB any field I want like: $objResult2["name"]; $objResult2["email"]; etc.
But what i do if i have in the table more rows with the same id_product?
I want to write a if statment, which counts if id_product repeats. How to do that? If it is a lot of work, atleast please give me an idea of the right tutorial that I must read. Because i am trying second day to fix this, and searched google but i didnt find what i need, or maybe i coulndt understand it....
This is my query
$sql_product = "SELECT * FROM ps_product AS prod";
$join_product = " LEFT JOIN ps_product_lang AS lang ON lang.id_product = prod.id_product";
$join2_product = " LEFT JOIN ps_stock_available AS stok ON stok.id_product = prod.id_product";
$where_product =" WHERE prod.id_category_default = $idp AND lang.id_lang = 8";
$sql_product = $sql_product.$join_product.$join2_product.$where_product;
$objQuery_product = mysqli_query($objConnect, $sql_product) or die ("Error Query [".$sql_product."]");
You can simple remove the same id_product using DISTINCT keyword in your query. Such as:
SELECT DISTINCT id_product FROM my_table
This will give you results with different ids only.
The second way of doing it is taking the output values inside an array.
In your while loop:
$my_array[] = $objResult2["id_product"];
Then using array_filter remove all the duplicates inside the array.
YOu can also use array_count_values() if you want to count the duplicate values.
Ok here we go. For example you are fetching data with this query.
select id_product, name from PRODUCTS;
Suppose above query gives you 5 records.
id_product name
1 bat
2 hockey
2 hockey
3 shoes
4 gloves
Now you got 2,2 and hockey, hockey. Instead of thinking this way that you have to introduce an if statement to filter repeating records or same name or id_product records.
Rewrite your sql query like this.
select distinct id_product, name from PRODUCTS;
Or if you need count of each then my friend you will write your query something like this...
Graham Ritchie, if Andrei needs count of each repeating record then we will do something like this in our query.
SELECT PRODUCT_ID,
COUNT(PRODUCT_ID) AS Num_Of_Occurrences
FROM PRODUCTS
GROUP BY PRODUCT_ID
HAVING ( COUNT(PRODUCT_ID) > 1 );
SELECT id_product,COUNT(*) AS count
FROM tablename
GROUP BY id_product;
This query will then return you two items in your query
$objResult2["id_product"] //and
$objResult2["count"]
The if statement is then just
if($objResult2["count"] > 1){
//Do whatever you want to do with items with more than 1 occurence.
//for this example we will echo out all of the `product_id` that occur more than once.
echo $objResult2["id_product"] . " occurs more than once in the database<br/>";
}

How can i do something additional with this MySQL query? in php

$SQL = "
DELETE male_users from male_users
LEFT JOIN
(
select id from male_users order by date_time DESC LIMIT 0, 100
) t1
ON male_users.id=t1.id
where t1.id is null
";
if($row_male[0] > 100){
$result = $mysqli->query($SQL) or die($mysqli->error.__LINE__);
}
I'm using this query to delete all names in a list past the most recent 100.
However, each of the names have a URL of an image on the server associated with them. How can I use this query and actually get the names of each of the items its deleting into a for loop to delete their corresponding image URLs?
Typically I'd want to use unlink(URL)
With a join query such as this, how do I get the actual returned row usernames?
First SELECT to get all the image IDs, then run DELETE combined with WHERE IN, and also unlink each image.
Pseudo code would be:
SELECT image_id, image_path FROM table WHERE condition;
Fill the results into an array, then:
DELETE ... WHERE id IN (your ids) // (1, 2, 3, 5, 100)
Then loop the array, and for each do:
unlink($image_path);
You didn't show us your table structures, but that's roughly how you could do it. And don't forget you need image server path, not the url, for unlink.

getting rid of repeated customer id's in mysql query

I originally started by selecting customers from a group of customers and then for each customer querying the records for the past few days and presenting them in a table row.
All working fine but I think I might have got too ambitious as I tried to pull in all the records at once having heard that mutiple queries are a big no no.
here is the mysqlquery i came up with to pull in all the records at once
SELECT morning, afternoon, date, date2, fname, lname, customers.customerid
FROM customers
LEFT OUTER JOIN attend ON ( customers.customerid = attend.customerid )
RIGHT OUTER JOIN noattend ON ( noattend.date2 = attend.date )
WHERE noattend.date2
BETWEEN '$date2'
AND '$date3'
AND DayOfWeek( date2 ) %7 >1
AND group ={$_GET['group']}
ORDER BY lname ASC , fname ASC , date2 DESC
tables are customer->customerid,fname,lname
attend->customerid,morning,afternoon,date
noattend->date2 (a table of all the days to fill in the blanks)
Now the problem I have is how to start a new row in the table when the customer id changes
My query above pulls in
customer 1 morning 2
customer 1 morning 1
customer 2 morning 2
customer 2 morning 1
whereas I'm trying to get
customer1 morning2 morning1
customer2 morning2 morning1
I dont know whether this is possible in the sql or more likely in the php
I finally worked out what I was missing.
In order to address the element of the array I needed to use, I needed to use a double bracket ie $customer_array[0][lname], $customer_array[1][lname]. I realise this is probably obvious to most but it was completely eluding me. The key to my understanding this was
print_r(customer_array) which I'd seen a lot but never got working properly.
Then it was just a case of pulling out all the database rows with:
$customer_array =array();
while($row1=mysql_fetch_assoc($extract1)){
$customer_array[] = $row1;
}
and then to loop through as I have a fixed number of records:
for ($x=0;$x<=900;)
{
echo $customer_array[$x][fname];
echo$customer_array[$x][lname];
for($y=0;$y<=30;$y++)
{
echo $customer_array[$x][morning];
echo $customer_array[$x][afternoon];
$x++;
}
}
Hope this helps someone else.
If I'm joining together related tables for one row (which is definitely a best practice as opposed to nested queries and should be done the majority of the time when you can), I tend to do the formatting into neat tables through code.
(pseudocode provided as i don't remember PHP):
// query database
while !EOF {
currentCustomerId = $database["CustomerId"]
// do opening table row stuff; customer name, etc.
while !EOF && currentCustomerId == $database["CustomerId"] {
// do the relational columns from the join
// move to next record
}
// do closing table row stuff
}
The outer loop iterates over each customer, and the inner loop iterates through the relational data for that customer.
Can you achieve that with SQL? Maybe, but I doubt it'd look nice.
Here is the easy PHP solution.
$mornings_by_customer = array();
foreach ($result as $r) {
$mornings_by_customer[$r['customerid']][] = $r['morning'];
}
An example of your result data structure and an example of what you'd rather have - in PHP's array notation - would allow me to give you a more exact answer. This, however, should give you the general idea.
Based also on this near identical problem I'm trying to help you solve, I know you're uncomfortable with arrays. But you're going to have to learn them if you're going to be coding PHP, especially if you need to deal with multidimensional ones as you seem to want to do here.
$sql = "SELECT morning, afternoon, date, date2, fname, lname, customers.customerid
FROM customers
LEFT OUTER JOIN attend ON ( customers.customerid = attend.customerid )
RIGHT OUTER JOIN noattend ON ( noattend.date2 = attend.date )
WHERE noattend.date2
BETWEEN '$date2'
AND '$date3'
AND DayOfWeek( date2 ) %7 >1
AND group ={$_GET['group']}
ORDER BY lname ASC , fname ASC , date2 DESC ";
$results = mysql_fetch_result($sql);
$customer_array = array()
// Load up an array with each customer id as the key and array full of mornings as the value
while($row = mysql_fetch_array($results)) {
array_push($customer_array[$row['customerid']], $row['morning']);
}
// For each customer ID, get the array of mornings
foreach ($customer_array as $customerID=>$morningArray) {
echo $customerID;
// For each morning array item, echo it out
forreach ($morningArray as $key=>$value) {
echo " $value";
}
}

Categories