MYSQL Innerjoin only show one record - php

I am busy with a ticket systeem and i have the question in a table, users information in an other table and the responses in an other table.
What i want is to get the Question (Table 1) with the user information by user ID and all the responses (also with user information by id)
Now i have the following code:
public function ticketSingle($id=""){
$sql = "
SELECT ticketSubmitted.*, users.Name, users.email, users.phone, ticketResponse.*
FROM ticketSubmitted
INNER JOIN users
ON users.id = ticketSubmittedUserId
JOIN ticketResponse
ON ticketId = ticketSubmittedID
WHERE ticketSubmittedID = '".$id."'
";
$result = $this->run($sql, $bind);
return $result[0];
}
Table 1 = ticketSubmitted (the question, with an userID "ticketSubmittedUserId")
Table 2 = users (The user information)
Table 3 = ticketResponse (The table with the reactions)
But if i Print the results i get only one record of the TicketResponse and what i want is all the reactions.
Can someone help me out?
This is what the function return:
Array
(
[ticketSubmittedID] => 1
[ticketSubmittedUserId] => 1
[ticketSubmittedDate] => 2018-02-05 16:00:00
[ticketSubmittedTitle] => Question Title
[ticketSubmittedMessage] => Hello World!
[ticketSubmittedUserIp] => XXX.XXX.XXX.XXX
[ticketSubmittedStatus] => 1
[Name] => John Doe
[email] => john#doe.com
[phone] => 0612345678
[ticketResponseId] => 1
[ticketId] => 1
[ticketUserId] => 2
[ticketMessage] => Hello Reaction
[ticketDate] => 2018-02-05 17:05
[ticketIp] => XXX.XXX.XXX.XXX
)

You are returning only the first row return $result[0]; 0 in the first index of the result. so you should return all eg:
return $result;
and loop over the result for manage what you need
foreach($result as $key => $value){
echo $value['ticketResponseId'];
}
You can check the real return content using
var_dump($result);

Related

How to query employee details and relate their performance metrics?

I am fetching the id, first name, and last name of all employees that are approved and not archived. Then I am looping these results and using the ids to query other tables to collect some count data.
I tried the below code, but I am not getting the expected output.
$queryEmp = "
SELECT id, firstname, lastname
FROM tbl_employee as e
WHERE is_archive=0 and is_approved=1
";
$getQuery= $this->db->query($queryEmp);
$result= $getQuery->result();
foreach ($result as $key=> $value) {
//echo "<pre>";
print_r($value);
$day = "MONTH(date_of_created) = DATE(CURRENT_DATE())";
$group = "f_id IN (SELECT MAX(f_id) FROM tbl_fileStatus GROUP BY f_bankid)";
$condiion = "and ba.createdby='" . $value->id . "' and " . $day ." and " . $group;
$query2 = "
select
(SELECT COUNT(c_id)
FROM tbl_lead
WHERE leadstatus='1' AND ".$day.") as confirmCount,
(SELECT COUNT(f_id)
FROM tbl_fileStatus as fs
join tbl_bankdata as ba on ba.bank_id=fs.f_bankid
WHERE fs.f_filestatus=1 " . $condiion . ") as disbursed,
(SELECT COUNT(f_id)
FROM tbl_fileStatus as fs
join tbl_bankdata as ba on ba.bank_id=fs.f_bankid
WHERE fs.f_filestatus=2 ".$condiion.") as filesubmit
";
# code...
$getQuery2= $this->db->query($query2);
$result2[]=$getQuery2->result();
}
echo "<pre>";
print_r(result2);
$result looks like this:
Array (
[0] => stdClass Object (
[id] => 1
[firstname] => xyz
[lastname] => xyz
)
...
)
Second query output:
Array (
[0] => Array (
[0] => stdClass Object (
[fallowCall] => 0
[confirmCount] => 0
[disbursed] => 0
[filesubmit] => 0
)
)
...
)
How can I produce the correct results which relate respective employees with with their performance metrics? Either this structure:
Array (
[0] => stdClass Object (
[id] => 1
[firstname] => xyz
[lastname] => xyz
[somename] => (
[fallowCall] => 0
[confirmCount] => 0
[disbursed] => 0
[filesubmit] => 0
)
)
...
)
Or this structure:
Array (
[0] => stdClass Object (
[id] => 1
[firstname] => xyz
[lastname] => xyz
[fallowCall] => 0
[confirmCount] => 0
[disbursed] => 0
[filesubmit] => 0
)
...
)
I have added the my table structure and some sample data here: https://www.db-fiddle.com/f/8MoWmKPuzTrrC3DQJsiX35/0
some notes here
1) createdby is the id of table tbl_employee
2) lead_id in the bank table is the c_id of the table tbl_lead
3) f_bankid in the tbl_fileStatus is the bank_id of the table tbl_bankdata
There is actually no need to create the additional depth/complexity just to hold the count data. Furthermore, by using a combination of LEFT JOINs to connect the related tables and apply your required conditional rules, you can achieve your desired result by making just one trip to the database. This will without question provide superior efficiency for your application. LEFT JOINs are important to use so that counts can be zero without excluding employees from the result set.
Also, I should point out that your attempted query was mistakenly comparing a MONTH() value against a DATE() value -- that was never going to end well. :) In fact, to ensure that your sql is accurately isolating the current month from the current year, you need to be also checking the YEAR value.
My recommended sql:
SELECT
employees.id,
employees.firstname,
employees.lastname,
COUNT(DISTINCT leads.c_id) AS leadsThisMonth,
SUM(IF(fileStatus.f_filestatus = 1, 1, 0)) AS disbursedThisMonth,
SUM(IF(fileStatus.f_filestatus = 2, 1, 0)) AS filesubmitThisMonth
FROM tbl_employee AS employees
LEFT JOIN tbl_lead AS leads
ON employees.id = leads.createdby
AND leadstatus = 1
AND MONTH(leads.date_of_created) = MONTH(CURRENT_DATE())
AND YEAR(leads.date_of_created) = YEAR(CURRENT_DATE())
LEFT JOIN tbl_bankdata AS bankData
ON employees.id = bankData.createdby
LEFT JOIN tbl_fileStatus AS fileStatus
ON bankData.bank_id = fileStatus.f_bankid
AND MONTH(fileStatus.date_of_created) = MONTH(CURRENT_DATE())
AND YEAR(fileStatus.date_of_created) = YEAR(CURRENT_DATE())
AND fileStatus.f_id = (
SELECT MAX(subFileStatus.f_id)
FROM tbl_fileStatus AS subFileStatus
WHERE subFileStatus.f_bankid = bankData.bank_id
GROUP BY subFileStatus.f_bankid
)
WHERE employees.is_archive = 0
AND employees.is_approved = 1
GROUP BY employees.id, employees.firstname, employees.lastname
The SUM(IF()) expression is a technique used to execute a "conditional count". "Aggregate data" is formed by using GROUP BY and there are specialized "aggregate functions" which must be used to create linear/flat data from these clusters/non-flat collections of data. fileStatus data is effectively piled up upon itself due to the GROUP BY call. If COUNT(fileStatus.f_filestatus) was called, it would count all of the rows in the cluster. Since you wish to differentiate between f_filestatus = 1 and f_filestatus = 2, an IF() statement is used. This is doing the same thing as COUNT() (adding 1 for every qualifying occurrence), but it is different from COUNT() in that it does not count specific rows (within the scope of the cluster) unless the IF() expression is satisfied. Another example.
Here is a db fiddle demo with some adjustments to your supplied sample data: https://www.db-fiddle.com/f/8MoWmKPuzTrrC3DQJsiX35/4 (The result set will only be "good" while the current is June of this year.)
After saving the above string as $sql, you can simply execute it and loop through the array of objects like this:
foreach ($this->db->query($sql)->result() as $object) {
// these are the properties available in each object
// $object->id
// $object->firstname
// $object->lastname
// $object->leadsThisMonth
// $object->disbursedThisMonth
// $object->filesubmitThisMonth
}

Querying a database with a one to many relationship

I am making a database that when users register, they pick 3 games they would like to play. the games are stored in a separate table (gameinfo) from the user information table (personalinformation). I am querying with the first game being shown but I would like all three shown for each user. How would I implement showing all the games?
I have tried to create different variables for each game, but that has seemed to not work as I expected and broke. the games when they are stored on the personalinformation table are stored as numbers like 1 or 2. these are linked to the gameinfo table and are the primary key for each game.
Structure of database
https://imgur.com/a/qee9C1t
$conn = mysqli_connect('localhost', 'root', '', 'esportclub');
$sql = "SELECT user_ID, username, Email, Gender, firstName, lastName, gameName FROM personalinformation, gameinfo WHERE game_id = firstGame";
$result = mysqli_query ($conn, $sql);
if (mysqli_num_rows($result) > 0) {
echo "<table>";
while($row = mysqli_fetch_assoc($result)) {
echo " <tr><td> Name: ". $row{"username"}. " </td><td> Email: ". $row{"Email"}. " </td><td> Gender: ". $row{"Gender"}. "</td>" .
"<td> First Name: ". $row{"firstName"}. " </td><td> First Game: ". $row{"gameName"}. "</td><td> Last Name: ". $row{"lastName"}. "</td>" . "</td></tr>" ;
}
echo "</table>";
}
else{
echo "0 results";
}
$conn->close();
As mentioned in my comment, I would create a table to associate users and games by storing unique pairs of user_ID and game_id values. Then I'd JOIN the tables together accordingly.
However, I see that you are storing three game values for each user in the personalinformation table, in columns named firstGame,secondGame, and thirdGame.
In that case, you can JOIN the game table to each of those columns.
So, with your existing structure:
SELECT
p.*,
game1.`gameName` as `firstGame_name`,
game2.`gameName` as `secondGame_name`,
game3.`gameName` as `thirdGame_name`
FROM `personalinformation` p
LEFT JOIN `games` as game1 ON (game1.`game_id` = p.`firstGame`)
LEFT JOIN `games` as game2 ON (game2.`game_id` = p.`secondGame`)
LEFT JOIN `games` as game3 ON (game3.`game_id` = p.`thirdGame`)
WHERE 1; // or WHERE p.`user_ID` = :user_ID;
EDIT
Since many users can own a game and a user can own many games, it sounds like a "many-to-many" relationship.
Here is my preferred method for that type of relationship. One advantage is that you don't need to limit the number of assigned games. That is, a user can own any number of games.
Create a third table to store unique user/game pairs.
It will tells you which games are assigned to which users.
Something like:
CREATE TABLE `user_game` (
`user_id` MEDIUMINT NOT NULL ,
`game_id` MEDIUMINT NOT NULL
);
ALTER TABLE `user_game`
ADD UNIQUE `unique pair` (`user_id`, `game_id`);
Then join the three tables together:
SELECT
u.*,
g.`game_id`,
g.`gameName`
FROM `personalinformation` u
LEFT JOIN `user_game` as ug ON ( ug.`user_id` = u.`user_ID` )
LEFT JOIN `games` as g ON ( g.`game_id` = ug.`game_id` )
WHERE 1;
You'll get back one row for every user/game relationship.
If one user has three games, that user will have three rows in the result, each row including one gameName.
For example:
Name Game
---- -----------------
Jane League of Legends
Jane Minecraft
Fred Dota 2
Alex Minecraft
Alex War Dragons
Alex Fortnite
More complex display might require some processing:
<?php
$users = array();
while($row= mysqli_fetch_object($result)) {
$uid = $row->user_ID;
// if this user isn't in the array...
if (!array_key_exists($uid,$users)) {
// ... create a user entry ...
$user = new stdClass();
$user->firstname = $row->firstName;
// ... and add it to the user array.
$users[$uid] = $user;
}
// if this row has a valid game ...
if (!empty($row->game_id)) {
// ... create a game entry ...
$game = new stdClass();
$game->id = $row->game_id;
$game->name = $row->gameName;
//.. and add the game to the user's entry
$users[$uid]->games[$game->id]=$game;
}
}
For a structure like this:
Array
(
[1] => stdClass Object
(
[firstname] => Jane
[games] => Array
(
[1] => stdClass Object
(
[id] => 1
[name] => Leage of Legends
)
[2] => stdClass Object
(
[id] => 2
[name] => Minecraft
)
)
)
[2] => stdClass Object
(
[firstname] => Fred
[games] => Array
(
[3] => stdClass Object
(
[id] => 3
[name] => Dota 2
)
)
)
[3] => stdClass Object
(
[firstname] => Alex
[games] => Array
(
[2] => stdClass Object
(
[id] => 2
[name] => Minecraft
)
[4] => stdClass Object
(
[id] => 4
[name] => War Dragons
)
[5] => stdClass Object
(
[id] => 5
[name] => Fortnite
)
)
)
)

Display Two tables data in Php

i have following tables
Author
id | author_name | author_detail | author_bio
books
id | author_id | book_name | book_detail
i want to display data in following way
Author Name ::
Author Detail ::
books :: 1.book1
2.book2
3.book3
4.book4
i have tried following query but didnt worked as per my requirement
select * from authors left join books on author.id=books.author_id
i have tried group concat but it gives books name with coma seperate.so i want to books detail in array
select author.author_name,author.author_detail,author.author_bio,group_concat(books.book_name) eft join books on author.id=books.author_id
i am expexting output like
Array
(
[0] => Array
(
[id] => 1
[name] => Norm
[books] => Array
(
[0] =>Array
(
[id] => 4
[book_name] => great wall
[created_at] => 2015-09-11 04:45:07
[updated_at] => 2015-09-11 04:45:07
)
[1] =>Array
(
[id] => 6
[book_name] =>new book
[created_at] => 2015-09-11 04:45:07
[updated_at] => 2015-09-11 04:45:07
)
)
)
[1] => Array
(
[id] => 2
[name] => Norm
[books] => Array
(
[0] =>Array
(
[id] => 2
[book_name] => amazing star
[created_at] => 2015-09-11 04:45:07
[updated_at] => 2015-09-11 04:45:07
)
[1] =>Array
(
[id] => 3
[book_name] =>way of journy
[created_at] => 2015-09-11 04:45:07
[updated_at] => 2015-09-11 04:45:07
)
)
)
i have checked this question also
displaying php mysql query result with one to many relationship
Can any one help me how to display data like above ?
thank you
Try this:
SELECT
A.id
A.author_name,
A.author_detail,
A.author_bio,
B.book_name,
B.created_at,
B.updated_at
FROM books AS B
LEFT JOIN author AS A
ON (A.id=B.author_id)
you will get result like this:
id | author_name | author_detail | author_bio | book_name
1 | ari | some detail | some bio | book_ari_1
1 | ari | some detail | some bio | book_ari_2
1 | ari | some detail | some bio | book_ari_3
2 | tester | some detail | some bio | book_tester_1
etc..
to make array as your expecting result you need to restructure your array result. i will asume your result array will be in $result variable
$new_result = array();
foreach ($result as $key => $value) {
if (empty($new_result[$value['id']]))
{
$new_result[$value['id']] = array(
'id' => $value['id'],
'name' => $value['name'],
'books' => array(
array(
'id' => $value['id'],
'book_name' => $value['book_name'],
'created_at' => $value['created_at'],
'updated_at' => $value['updated_at']
),
)
)
}
else
{
$new_result[$value['id']]['id'] = $value['id'];
$new_result[$value['id']]['name'] = $value['name'];
$new_result[$value['id']]['books'][] = array(
'id' => $value['id'],
'book_name' => $value['book_name'],
'created_at' => $value['created_at'],
'updated_at' => $value['updated_at']
);
}
}
the result will look like your expected. but the key number will be formated as id.
to reset key of $new_result as increment number you need to get only value use array_values() function
$new_result = array_values($new_result);
You could do it with your first query...but you'd have to check the author_id inside the record loop and show the author details only whenever the value changed (by comparing it with a value stored in a variable)...otherwise only show the book details.
So your code might (very roughly) look like this:
$query = "select whatever whatever...";
$records = $database->Execute($query);
foreach ($records as $fields) {
if ($fields['id'] != $previous_id) echo "Author ...";
echo "Book whatever whatever ...";
$previous_id = $fields['id'];
}
A more straightforward (although slightly longer) way would be to have a second query: a sub-query. And it would take place inside the loop through the results of the first (outer) query. So your outer query gets the authors and, after you show the author details, you have this separate query for books of the author...and you have a loop-within-the-outer-loop to show the details of each book.
So your code (very roughly) looks something like this:
$query = "select id, author_name, whatever from author";
$author_records = $database->Execute($query);
foreach ($author_records as $fields) {
echo "Author: {$fields['author_name']} whatever <br/>";
$subquery = "select whatever from books where id = whatever";
$book_records = $database->Execute($subquery);
foreach ($book_records as $otherfields) {
echo "Book whatever whatever";
}
}
you can do this in php no need to go in query itself but take both data in separate query i.e. books and author data
Remember i assumed $result as authors data and $result2 as books data
$item=array();
while($row=mysql_fetch_array($result))
{
$id=$row['id'];
$item[$id]['name']=$row['name'];
$item[$id]['id']=$row['id'];
$item[$id]['books']=array();
$temp=array();
while($row1=mysql_fetch_array($result2))
{
if($id==$row1['author_id'])
{
$temp['id']=$row1['id'];
$temp['book_name']=$row1['book_name'];
$temp['created_at']=$row1['created_at'];
$temp['updated_at']=$row1['updated_at'];
array_push($item['id']['books'],$temp);
}
}
}
Now here id is formatted as author's id. To get like array keys you can use array_values($item)

PHP PDO LEFT JOIN Multidimensional Array

Basically, I have three tables. I have a projects table, a questions table and an answers table. A project can have many questions and a question can have many answers. Using PDO's and LEFT JOIN ON the Question ID, how can I turn comments with answers into a multidimensional array so that the structure would look like this:
[Question] => Array
(
[id] => 1
[question] => 'Random Question'
[askedBy] => 123
[answer] => Array
(
[0] => Array
(
[id] => 1
[answer] => 'An Answer'
[answeredBy] => 123
)
[1] => Array
(
[id] => 1
[answer] => 'Another Answer'
[answeredBy] => 123
)
)
)
Finalized Code (which is returning what I want)
$questions = array();
$questionCounter = 0;
$questionID = NULL;
$STH = $DBH->query("SELECT `project_question`.`id` AS question_id, `project_question`.`question`, `project_question`.`userID` AS askedBy,
`project_question`.`created` AS question_created, `project_answer`.`id` AS answer_id,
`project_answer`.`answer`, `project_answer`.`userID` AS answeredBy,
`project_answer`.`accepted`, `project_answer`.`created` AS answer_created
FROM `project_question`
LEFT JOIN `project_answer`
ON `project_question`.`id` = `project_answer`.`questionID`
WHERE `project_question`.`projectID` = $args[0]
AND `project_question`.`projectPhase` = 2");
while($row = $STH->fetch(PDO::FETCH_ASSOC)){
if($row['question_id'] !== $questionID){
$questions[$questionCounter] = array(
'id' => $row['question_id'],
'question' => $row['question'],
'userID' => $row['askedBy'],
'created' => $row['question_created'],
'answers' => array()
);
array_push($questions[$questionCounter]['answers'],
array(
'id' => $row['answer_id'],
'answer' => $row['answer'],
'userID' => $row['answeredBy'],
'accepted' => $row['accepted'],
'created' => $row['answer_created']
));
$questionCounter++;
$questionID = $row['question_id'];
} else {
array_push($questions[$questionCounter - 1]['answers'],
array(
'id' => $row['answer_id'],
'answer' => $row['answer'],
'userID' => $row['answeredBy'],
'accepted' => $row['accepted'],
'created' => $row['answer_created']
));
}
}
In one query, you can request all answers, join questions to them, and join projects to questions.
Create empty array $projects = array()
Iterate through every resulting row foreach ($rows as $row)
Add project with its data to array, if it does not exist already (use project id as key) if (!isset($projects[$row->project_id])) { $projects[$row->project_id] = array('col1' => $row->col1,'questions' => array()); }
Add question with its data to project questions array, if it does not exist already (use question id as key) if (!isset($projects[$row->project_id]['questions'][$row->question_id])) { $projects[$row->project_id]['questions'][$row->question_id] = array('col2' => $row->col2,'answers' => array()); }
Add answer with its data to project question answers array (use answer id as key) $projects[$row->project_id]['questions'][$row->question_id]['answers'][$row->answer_id] = array('col3' => $row->col3);
But as you can understand, you will get many useless information in that query. You could go with one query, getting projects only, iterate through them, in each cycle add data to array and query again to get questions that has specific project_id, iterate through them, in each cycle add data to array and query again to get answers that has specific question_id, iterate through them, and add data to array.
But if I rethink this, I think MySQL will work faster than PHP, even with returning bunch of useless data (I mean, repeating data about projects and questions) and 1 query vs possible 50 queries from one client is much better, so I suggest better use first method.
Without further information about your database table and columns, you wont get from me anything more than pseudo-code-algorithm.
EDIT: Possible MySQL select query:
SELECT
a.id answer_id, a.answer, a.answeredBy,
q.id question_id, q.question, q.askedBy,
p.id project_id, p.title
FROM answer a
LEFT JOIN question q ON q.id = a.question_id
LEFT JOIN project p ON p.id = q.project_id
For table structure
project -> | id | title |
question -> | id | question | askedBy | project_id |
answer -> | id | answer | answeredBy | question_id |

MySQL pulling information from multiple table issue

I'm trying to access information from 2 different tables and its retrieving the information but it all so pulling in user information multiple times pending how many fruits listed in table tbl_fruits.
like to be able to display user information once and pull what ever number of fruits associated with the user at the same time.
2 tables:
tbl_users:
userid
firstname
lastname
tbl_fruits:
userid
fruit
in the example code userID 4 has 3 fruits associated with him in tbl_fruit. As you can see from the results below the user information is listed multiple times. How can I rewrite the code so that the user information is pulled once and the fruits show up 3 times.
$clientID = "4";
try
{ $stmt = $dbcon1 ->query("SELECT
tbl_fruits.fruit,
tbl_users.userid,
tbl_users.firstname,
tbl_users.lastname
FROM tbl_users
LEFT JOIN tbl_fruits
ON tbl_fruits.userid = tbl_users.userid
WHERE tbl_users.userid = '$clientID' ");
$testArray = $stmt->fetchAll(PDO::FETCH_ASSOC);
}
catch(PDOException $e)
{ echo $e->getMessage(); }
echo '<pre>';
print_r($testArray);
echo '</pre>';
results
array
(
[0] => Array
(
[fruit] => Apple
[userid] => 4
[firstname] => John
[lastname] => Smith
)
[1] => Array
(
[fruit] => Orange
[userid] => 4
[firstname] => John
[lastname] => Smith
)
[2] => Array
(
[fruit] => Banana
[userid] => 4
[firstname] => John
[lastname] => Smith
)
)
Change your query as below:
{ $stmt = $dbcon1 ->query("SELECT
count(tbl_fruits.userid)
tbl_users.userid,
tbl_users.firstname,
tbl_users.lastname
FROM tbl_users
LEFT JOIN tbl_fruits
ON tbl_fruits.userid = tbl_users.userid
WHERE tbl_users.userid = '$clientID'
GROUP BY tbl_users.userid ");
The count(tbl_fruits.userid) part counts the number of unique rows with that row's value of tbl_fruits.userid, while the GROUP BY tbl_users.userid part eliminates the duplicates.
Be sure to put an index on tbl_users.userid and tbl_fruits.userid for best performance.

Categories