I'm pretty new to databases, so my question is:
Let's say that we have two tables: Users and Orders
Is it possible (and how do I do it) to list all users with their data (First & Last name, birthdate etc) and associated orders in one query? So the result should look something like this:
|------------------------------|
| John Doe | Order 1 details |
| | Order 2 details |
| | Order 3 details |
|------------------------------|
| Janny Hoe | Order x details |
| | Order y details |
|------------------------------|
So you got the point? Each row from table1 has a field which contains multiple rows from table2? I've heard MySQL doesn't return multidimensional arrays, so how does it return something like this?
Any help would be greatly appreciated!
EDIT:
Table structure could be something like this:
TABLE users:
id | name
TABLE orders:
id | user_id | date_ordered | other unrelevant data...
I know this is doable with joins, but what bugs me is what will it return?
Will result have field orders which would be array containing orders row data like $result[0]['orders'][0]['date_ordered'] or something like that ?
Do a LEFT join (if there is a possibility that a user does not have any orders) and then gather the results in an array, based on the user ID:
SELECT Users.id, Users.name, Order.detail
FROM Users
LEFT JOIN Order
ON Users.id= Order.user;
Ex:
$userOrders = array();
$sql = 'SELECT Users.id, Users.name, Order.detail
FROM Users
LEFT JOIN Order
ON Users.id= Order.user';
foreach ($pdo->query($sql) as $row) {
$userOrders[$row['user_id']][] = $row;
}
Related
In some controller in my website I had to write all this sql query to get the results that I need since I don't think / know that Laravel Eloquent ORM can provide something very specific like this
DB::select('
SELECT users.id,
users.firstname,
users.lastname,
users.slug,
profiles.bio,
profiles.gender,
profiles.verified,
profiles.investor,
profiles.photo,
countries.name AS country,
interests.name AS interests,
specialities.name AS specialities
FROM users
JOIN profiles ON profiles.user_id = users.id
JOIN countries ON profiles.country_id = countries.id
JOIN interests_profiles ON interests_profiles.profile_id = profiles.id
JOIN interests ON interests_profiles.interest_id = interests.id
JOIN profiles_specialities ON profiles_specialities.profile_id = profiles.id
JOIN specialities ON profiles_specialities.speciality_id = specialities.id
');
However, When i return-ed the results of this query i got a very weird results where the query will return each user multiple times depending on the number of the (interests & specialities) that is associated with his profile.id
Something almost similar to this:-
---------------------------------------------------------------------
| users.id | users.firstname | ...etc... | interests | specialities |
---------------------------------------------------------------------
| 8 | Jhon | ...etc... | skydiving | Laravel |
| 8 | Jhon | ...etc... | football | JavaScript |
| 10 | Daved | ...etc... | Chatting | Physics |
| 10 | Daved | ...etc... | Driving | Engineering |
| 11 | Steve | ...etc... | Writing | Woodworks |
---------------------------------------------------------------------
So in summary what I got is that the query loops through the user many times as much as he have specialities & interests associated with his profile id.
Note that I linked the profiles table with the interests & specialities tables using pivot mid tables (interests_profiles and profiles_specialities) respectively, And I put only on them profiles_id and interest_id/speciality_id as foreign keys.
I don't know if there is any Laravel Eloquent way to get this done, because I need to filter my users based on their interests with "WHERE" clause, for example: 'WHERE intrests.name = Volleyball'?
If not, Then how to get the query to run one time only per user, so the results could be something like this:-
[{"users.id": 8, "users.firstname": 'Jhon', ...etc..., "interests":{"skydiving", "football"}, "specialities": {"Laravel", "JavaScript"}}]
And then I can loop through interests and specialities in the view.
I hope that i explained the problem well, And i apologise for prolongation.
Thanks in advance.
If you are using MySQL, you can use GROUP BY users.id AND GROUP_CONCAT, something like:
SELECT users.id,
users.firstname,
users.lastname,
users.slug,
profiles.bio,
profiles.gender,
profiles.verified,
profiles.investor,
profiles.photo,
countries.name AS country,
GROUP_CONCAT(DISTINCT interests.name) AS interests,
GROUP_CONCAT(DISTINCT specialities.name) AS specialities
FROM users
JOIN profiles ON profiles.user_id = users.id
JOIN countries ON profiles.country_id = countries.id
JOIN interests_profiles ON interests_profiles.profile_id = profiles.id
JOIN interests ON interests_profiles.interest_id = interests.id
JOIN profiles_specialities ON profiles_specialities.profile_id = profiles.id
JOIN specialities ON profiles_specialities.speciality_id = specialities.id
GROUP BY users.id
Probably you can find a way to do it also in Laravels ORM since it seems like a very flexible framework.
I have a problem at the moment where I'm trying to get all rows plus a selected row from my tables.
So I have three tables - users, tasks, and a joining table called tasks_users
The latter table just contains two columns - task_id and user_id, for the purpose of normalization.
I have a form to edit a task. The problem arises when I want to retrieve ALL users (so the task can be reassigned) and I also want to show the CURRENT user. Given my current queries I can only get all the users, or just the single related user.
Am I overlooking something obvious, or do I need a more complex query? Or perhaps a couple of queries?
Further clarification:
Imagine you have an "edit task" form and on it you have the user currently assigned. I want to also show all other users, so that I may reassign. Given that I have three tables I'm struggling to construct a query that returns what I want. Currently I can only return ALL user OR the single assigned user.
It seems it's not about the current user, but the task assignee. No matter who assigns the task, he should not be able to assign it to the current assignee.
If only one user can be assigned to a particular task, you can remove task_users table, because simply adding column user_id in table tasks will do the same job.
Let's say you have in table users
id | username |
---------------------
1 | A |
2 | B |
3 | C |
4 | X |
5 | Y |
And in table tasks
id | title | user_id |
-----------------------------------
1 | Bla | 3 |
2 | Asd | NULL | // if this is even possible
If you want to retrieve who you can assign to task_id = 1 (Bla), you can simply do:
$currentTaskID = 1; // or however you retrieve them, it's just for the explanation purpose
SELECT id, username FROM users WHERE id != (SELECT user_id FROM tasks WHERE id = $currentTaskID);
The output will be:
id | username |
---------------------
1 | A |
2 | B |
4 | X |
5 | Y |
If a task can be assigned to more than one user, and you will keep task_users table, we can imagine you have there:
task_id | user_id |
-------------------------
1 | 3 |
2 | NULL |
1 | 5 |
You can query this way:
$currentTaskID = 1; // or however you retrieve them, it's just for the explanation purpose
SELECT id, username FROM users WHERE id NOT IN (SELECT user_id FROM task_users WHERE task_id = $currentTaskID);
So the output will be:
id | username |
---------------------
1 | A |
2 | B |
4 | X |
If you permit NULL values in assignee, so a task is not assigned to anyone, the SELECT will return all users, because of WHERE id != NULL when you have no NULL id's in users
For the purpose of showing the current user somewhere, but not available for assigning, you should separate the queries in functions/methods.
Saying you have:
function getAvailableAssignees($task_id) {
$sql = "SELECT id, username FROM users WHERE id != (SELECT user_id FROM tasks WHERE id = $task_id);";
$this->query($sql);
return $this->result();
}
and
function getCurrentAssignee($task_id) {
$sql = "SELECT user_id FROM tasks where id = $task_id;";
$this->query($sql);
return $this->result();
}
So once you need to show the available assignees, you call the respective method, so do, when you need to show the current assignee.
I think you might be looking for a UNION ALL
SELECT username, status from table
UNION ALL
SELECT username, status from table where status = 'current' LIMIT 1
Make sure that amount of columns from first query matches the amount of columns from second query. Don't do SELECT * FROM in one query and SELECT username from in another.
I think you should do 2 queries, not 1.. It doesn't seem like the users table should be in the same data selection as the tasks and users selection.
If you insist on combining the results you can do use UNION DISTINCT to combine the results of 2 queries.
THe first query decides the columns to be returned so you should set it to be the joined tables since those are more columns. The users should also fit in the columns of the joined select since it already contains them.
Thank you for all the replies. I have however managed to fix the issue using a nested foreach loop:
<ul>
<?php foreach($stages as $stage):?>
<li>
<label>
<?php echo $stage['stage_id']; ?>
<input type="checkbox" name="stages[]" value="<?php echo $stage['stage_id']; ?>"
<?php
// loop through the assigned stages. if it matches the stage ID then echo checked
foreach ($assigned_stages as $assigned_stage)
{
if ($stage['stage_id'] === $assigned_stage['stage_id'])
{
echo 'checked';
}
}
?>
/>
<?php echo $stage['name']; ?>
</label>
</li>
<?php endforeach; ?>
</ul>
This is a very common case and I'm still unsure if this is the best approach, however it works without issue and there isn't a great deal of code involved, so for the time being I'm happy.
I have two tables :
product_list :
id_list | name_product | price |
1 | test01 | 20 |
10 | test02 | 50 |
people :
people_id | people_use_product | people_list
35 | test01 | 1
36 | test02 | 1
They have access to the list id 1 and 10. But the same product can be in both row. ( because the list can be used for many list people ).
I have to get only one row. ( = the price of the product )
SELECT * FROM people
INNER JOIN product_list ON (id_list=1 or id_list=10)
WHERE people_list = 1
LIMIT 0,100
How can I have only one row ?
Your request is wrong. You did not specified an adequate join condition. Your JOIN is actually making a cartesian product of the two tables, that's all.
If people.people_list is your foreign key to product_list :
SELECT * FROM people
INNER JOIN product_list ON (id_list = people_list) -- valid JOIN condition between two tables
WHERE ids_list = 1
may be closer to your needs.
However, I don't really understand your data structure and your real needs so you'll have to refine the query a bit, I guess...
I have a set of approx 9000 tutor ids in an array and i have put them in a string like:
(1,2, 3, 4,5,6,7,....9000,9001,9002)
so that i can use them in the following query:
select count(student_assignment.assignment_id) as total_assignment from
student_assignment, assigned_tutor_fk where assignment_status = 'closed'
and assigned_tutor_fk in (1,2, 3, 4,5,6,7,..100,101,103...9000,9001,9002)
group by assigned tutor_fk.
I want to calculate total number of rows associated with each tutor(assigned_tutor_fk), and those tutors which do not have an assignment ie those which do not have assignment
record in the table i want to show their assignment count as 0, and i just want my query to return count and assigned_tutor_fk
my table structure is:
assignment_id | assigned_tutor_fk | assignment_date | student_id |
| 1 | 2 | 22-01-2011 | 4 |
| 2 | 3 | 14-03-2011 | 5 |
Im trying to get my output to be like this:
|total_assignment | assigned_tutor_fk |
| 5 | 4 |
| 2 | 7 |
| 0 | 8 |
Update: I tthink i have not been able to express myself properly,i already have a list of tutors filtered on another criteria, it was very complex to combine these two queries so now i have a set of the tutor id's and i want the sum to be displayed as zero in case the tutors does not have assignment record. please help me on this as i don know wht to do now
SELECT t.id, COUNT(sa.assignment_id)
FROM tutor t
LEFT JOIN
student_assignement sa
ON sa.assignment_tutor_fk = t.id
WHERE t.id IN (1, 2, ..., 9002)
GROUP BY
t.id
dont put the tutors in a string. Select them from a table and do a LEFT JOIN with the assignment and FK table. Without knowing all of your tables, i'm guessing it would look like this:
select
t.tutorId,
count(sa.assignment_id) as total_assignment
from
tutor t
LEFT JOIN
assigned_tutor_fk fk
ON
fk.assigned_tutor_fk = tutor.tutorId
LEFT JOIN
student_assignment sa
ON
fk.assignment_id = sa.id
where
sa.assignment_status = 'closed' OR
ISNULL(sa.assignment_status) -- if join fails.
group by
t.tutorId
Left Join retrieves all your values from the tutor table and merges it with the joined table IF there is a match. If not, NULL is inserted.
SELECT
count(*) as total_assignment,
assigned_tutor_fk
FROM assignmentTable
GROUP BY assigned_tutor_fk
I am trying to query 6 separate tables in my mysql database, the structures are as follows;
item
itemitemid | item | description | brand | date | time | path |
actor
actoractorid | name | actorthumb | bio |
brand
brandbrandid | brandname | description | image |
movie
moviemovieid | title | genre | year | moviethumb | synopsis|
users
userid | name | surname | email | password |
request
requestid | userid | itemid | brandid | movieid | actorid | content | requestdate |
Using the following query I can display for example where the requestid=1 I can see the movie in the request, the actor in the movie, the item of clothing they were wearing and its brand.
$requestid = mysql_real_escape_string($_GET['requestid']);
$query = "select r.requestid, m.*, a.*, i.*, b.*
FROM request r INNER JOIN movie m ON m.movieid = r.movieid
INNER JOIN actor a ON a.actorid = r.actorid
INNER JOIN item i ON i.itemid = r.itemid
INNER JOIN brand b ON b.brandid = r.brandid
WHERE r.requestid = $requestid";
However when I try to echo out "content" and "request date" from the request table. The data simply doesn't appear. I also cannot get the info from the user table, e.g the user logging the request by by adding the following join;
$query = "select r.requestid, m., a., i., b., u.*
INNER JOIN users u ON u.userid = r.userid
Please advise?
You aren't SELECTing those fields. Right now, you're only SELECTing r.requestid from the requests table. You need to add references to every field you want to echo.
As far as the User join, you just seem to be joining on the wrong field. You need to join on u.userid = r.userid. Right now, you're joining on u.itemid which doesn't exist. You'll also need to change your SELECT statement to report the fields you want (e.g. SELECT ... , u.name, u.email).
As an aside, you should avoid SELECTing table.* where possible. This can break things when you add a field to a table but don't account for that when processing the results of a query. You should try to be explicit as possible, and SELECT only the fields you want to use - e.g. SELECT users.name, users.email rather than doing SELECT users.*.