MySQL - inner join - add column with value based on other value - php

I'm struggling with mysql joins :/
I've multiple tables inside database fe. tasks, users etc.
Table tasks containing tasks with various variables, but the most important - id's of users signed to task (as different roles inside the task - author, graphic, corrector):
+---------+-------------+--------------+
| task_id | task_author | task_graphic |
+---------+-------------+--------------+
| 444 | 1 | 2 |
+---------+-------------+--------------+
Table users
+---------+----------------+------------+-----------+
| user_id | user_nice_name | user_login | user_role |
+---------+----------------+------------+-----------+
| 1 | Nice Name #1 | login1 | 0 |
+---------+----------------+------------+-----------+
| 2 | Bad Name #2 | login2 | 1 |
+---------+----------------+------------+-----------+
Using PDO I'm getting the whole data I want while using INNER JOIN with data from different tables (and $_GET variable)
SELECT tasks.*, types.types_name, warehouse.warehouse_id, warehouse.warehouse_code, warehouse.warehouse_description
FROM tasks
INNER JOIN types ON types.types_id = tasks.task_id
INNER JOIN warehouse ON warehouse.warehouse_id = tasks.task_id
WHERE tasks.task_id = '".$get_id."'
ORDER BY tasks.task_id
Above query returns:
+---------+--------------+--------------+----------------+------------+-----------+------------------+------------------------+------------+-------------+-----------------+-----------+----------------+--------------------+---------------------+-----------+---------------------+------------------+---------------------+
| task_id | task_creator | task_graphic | task_purchaser | task_title | task_lang | task_description | task_description_files | task_files | task_status | task_prod_index | task_type | task_print_run | task_print_company | task_warehouse_code | task_cost | task_time_added | task_deadline | task_date_warehouse |
+---------+--------------+--------------+----------------+------------+-----------+------------------+------------------------+------------+-------------+-----------------+-----------+----------------+--------------------+---------------------+-----------+---------------------+------------------+---------------------+
| 2 | 1 | 2 | 1 | Test | PL | Lorem ipsum (?) | | | w | 2222 | 3 | 456546 | Firma XYZ | 2 | 124 | 29.09.2016 15:48:20 | 01.10.2016 12:00 | 07.10.2016 14:00 |
+---------+--------------+--------------+----------------+------------+-----------+------------------+------------------------+------------+-------------+-----------------+-----------+----------------+--------------------+---------------------+-----------+---------------------+------------------+---------------------+
And I'd like to get query with added user_nice_name after task_creator, task_author and task_graphic - obviously nice names selected from table users based on ID's provide in 3 above fields fe.
+---------+--------------+------------------------------------+--------------+--------------------------------------+
| task_id | task_creator | task_creator_nn | task_graphic | task_graphic |
+---------+--------------+------------------------------------+--------------+--------------------------------------+
| 2 | 1 | Nice Name (from task_creator ID=1) | 2 | Nice Name (from task_graphic ID = 2) |
+---------+--------------+------------------------------------+--------------+--------------------------------------+
How can I achieve that?

You need three joins:
SELECT t.*,
uc.user_nice_name as creator_name,
ug.user_nice_name as graphic_name,
up.user_nice_name as purchaser_name,
ty.types_name, w.warehouse_id, w.warehouse_code, w.warehouse_description
FROM tasks t INNER JOIN
types ty
ON ty.types_id = t.task_id INNER JOIN
warehouse w
ON w.warehouse_id = t.task_id LEFT JOIN
users uc
ON uc.user_id = t.task_creator LEFT JOIN
users ug
ON ug.user_id = t.task_graphic LEFT JOIN
users up
ON up.user_id = t.task_purchaser
WHERE t.task_id = '".$get_id."'
ORDER BY t.task_id;
Notes:
Table aliases make the query easier to write and to read. They are also required because you have three references to users in the FROM clause.
This uses LEFT JOIN for the users in case some of the reference values are missing.
You need to work on your naming. It doesn't make sense that a "warehouse" id matches a "task" id. Or that a "task" id matches a "types" id. But that is how you phrased the query in your question.
The ORDER BY effectively does nothing, because all rows have the same task_id.

Assuming that the task_graphic_name is inside a table name task_graphic_table and the relation field are task_graphic_id
SELECT tasks.*
, types.types_name
, warehouse.warehouse_id
, warehouse.warehouse_code
, warehouse.warehouse_description
, users.user_nice_name
FROM tasks
INNER JOIN types ON types.types_id = tasks.task_id
INNER JOIN warehouse ON warehouse.warehouse_id = tasks.task_id
INNER JOIN users ON users.user_nice_name = tasks.task_graphic
WHERE tasks.task_id = '".$get_id."'
ORDER BY tasks.task_id
And if you need the column appear in a specific order you should explicitally call the column name in sequence eg:
SELECT tasks.col1
, task.col2
, types.types_name
, warehouse.warehouse_id
, warehouse.warehouse_code
, task.col2
, warehouse.warehouse_description
, task_graphic_table.task_graphic_name

Add two sub query in with your query. like
SELECT tasks.*,
....
....,
(select user_nice_name from users where id = tasks.task_author) AS task_creator_name,
(select user_nice_name from users where id = tasks.task_graphic) AS task_graphic_name
FROM tasks
INNER JOIN types ON types.types_id = tasks.task_id
....
....

Related

How do I select distinct rows and cross check in another table?

I have 3 tables, users and tasks and completed_tasks. So basically I want to select all tasks where the user_id = 2 AND also check that the task does not exist in another table` the So here is my tables:
users table:
+----+-------+
| id | name |
+----+-------+
| 1 | John |
| 2 | Sally |
+----+-------+
tasks table:
+----+-----------+---------+
| id | task_name | user_id |
+----+-----------+---------+
| 1 | mop floor | 2 |
| 2 | dishes | 1 |
| 3 | laundry | 2 |
| 4 | cook | 2 |
+----+-----------+---------+
completed_tasks table:
+----+---------+---------+
| id | task_id | user_id |
+----+---------+---------+
| 1 | 1 | 2 |
+----+---------+---------+
Here is my current SELECT code for my MySQL database:
$db = "SELECT DISTINCT tasks.task_name, users.name FROM tasks LEFT JOIN ON users.id = tasks.user_id WHERE tasks.user_id = 2";
THe problem I'm having is: I want it to search in completed_tasks table and if the task exists, then don't select that task.
I tried to do that by adding the following but it did not work:
LEFT JOIN completed_tasks ON completed_tasks.user_id = 2
That did not work because if I had multiple completed tasks, it would just ignore it all together.
I want the end result should return the user's name and task name of task 3 and 4.
Also, performance is critical in my application. I could use PHP and loop through the arrays and do SELECT for each of them but that would not be good for performance.
You have a few ways to do this.
You can use a LEFT JOIN and then check for NULL in the optional table.
SELECT a.name, b.task_name
FROM users a
JOIN tasks b ON a.id = b.user_id
LEFT JOIN completed_tasks c ON c.task_id = b.id AND c.user_id = b.user_id
WHERE c.id IS NULL
;
You can do a NOT EXISTS sub-query
SELECT a.name, b.task_name
FROM users a
JOIN tasks b ON a.id = b.user_id
WHERE NOT EXISTS (
SELECT 1
FROM completed_tasks c
WHERE c.task_id = b.id AND c.user_id = b.user_id)
;

mysql select where left join syntax

I have a problem. I have 2 database tables.
table 1 people:
+----------+--------------+
| id | name |
+----------+--------------+
| 1 | johanalj |
| 2 | hjgjhggjh |
+----------+--------------+
table 2 images of people:
+----------+--------------+----------------+
| id | url | people_ID |
+----------+--------------+----------------+
| 1 | 3765345.png | 1 |
| 2 | 87e58974.png | 1 |
+----------+--------------+----------------+
Now I want to select person with id 1 from table 1 and all pictures from table 2 that have people_ID 1.
I tried LEFT JOIN in combination with a WHERE but cant get it to work
$sql = "SELECT * FROM people p LEFT JOIN images i ON i.people_ID = p.id WHERE id = '1'";
But I get a no result massage. What am I doing wrong?
There is an error(ambiguous column id). Both tables have id column. You need to add the table alias with id. try with -
$sql = "SELECT * FROM people p LEFT JOIN images i ON i.people_ID = p.id WHERE p.id = '1'";

JOIN rows from 3 tables WHERE tableA.column1 = tableB.column1 = tableC.column1

I have 3 tables, structured like so:
TABLE A:
ID | PCID | ACTIVE | COHORT | WEEKLY_MEETING_TIME | FYE_ID | RC | AGREEMENT_SIGNED | RELEASE_SIGNED | NOTES | FACULTY_ADVISOR
TABLE B:
ID | QUARTER | OFFICE | WRITING_CENTER | etc.. | etc.. | etc.. |
TABLE C:
ID | QUARTER | WEEK | EMAIL | etc.. | etc.. | etc.. |
The common element between all 3 tables is the ID field.
I need to SELECT from all 3 tables, and have each row represent one ID and all the values associated with that ID.
So, for example, each output row should look like a combination of the three tables:
RESULTS:
ID | PCID | ACTIVE | COHORT | WEEKLY_MEETING_TIME | FYE_ID | RC | AGREEMENT_SIGNED | RELEASE_SIGNED | NOTES | FACULTY_ADVISOR | QUARTER | OFFICE | WRITING_CENTER | etc.. | etc.. | etc.. | WEEK | EMAIL | etc.. | etc.. | etc.. |
I have no idea how to structure a query like this. I suspect it involves using JOINs but my attempts have proved futile.
how can I combine the data from 3 tables, based on shared ID field?
SELECT * FROM TABLEA
INNER JOIN TABLEB ON TABLEA.ID = TABLEB.ID
INNER JOIN TABLEC ON TABLEA.ID = TABLEC.ID
If you don't need all the values substitute the "*" with the names of the fields you need (ex. TABLEA.ID, TABLEB.QUARTER, TABLEC.WEEK...)
NATURAL JOIN works in MySQL:
select * from A natural join B natural join C
Try this :
SELECT / WHAT YOU NEED TO SELECT - NOT * !!!/
FROM TABLEA
INNER JOIN TABLEB USING (ID)
INNER JOIN TABLEC USING (ID)

how do i select data from multiple columns from two tables where there is a common column in both?

seems like a cake walk, because of the common column thing, but i've looked and i've looked and can't find the answer anywhere. there may be very similar things people are trying to do, but everyone always needs it slightly different than how i need it. anyway here goes...
jobs table
+----+--------+----+----+----+
| id | userid | i1 | i2 | i3 |
+----+--------+----+----+----+
| 1 | 1 | a | k | t |
| 2 | 1 | b | l | u |
| 3 | 1 | c | m | v |
| 4 | 2 | d | n | w |
| 5 | 2 | f | o | x |
| 6 | 2 | g | p | y |
| 7 | 3 | h | q | z |
| 8 | 3 | i | r | a |
| 9 | 4 | j | s | b |
+----+--------+----+----+----+
user_table table
+--------+----+----+----+
| userid | fn | ln | i4 |
+--------+----+----+----+
| 1 | a | b | w |
| 2 | c | d | x |
| 3 | e | f | y |
| 4 | g | h | z |
+--------+----+----+----+
i want to select multiple columns from one table and multiple columns from another table, and the amount of columns don't have the same amount. so if i'm selecting id, i1, i2, and i3 from jobs table and selecting fn, ln, and i4 from user_table table, then that means i'm selecting 4 pieces of info from jobs table and 3 pieces of info from user_table table.
so let's say i want to select a specific job and display the info for that job, but also i want to display the info of the user that belongs to the job then it might go something like this...
job 1:
id: 1, i1: a, i2: k, i3: t, fn: a, ln: b, i4: w
for job 4 it would be:
id: 4, i1: d, i2: n, i3: w, fn: c, ln: d, i4: x
the jobs table and user_table table have the common column of userid. so how do i write my query to do the above using this common column?
i tried all sorts of things with SELECT and WHERE and AND and JOIN and UNION and AS and GROUP and BY and writing the table names separate from the column names and writing the table names and column names together with a period in between. i just can't find the correct way to write this query.
in these examples below that don't work i'm just trying to select one thing from the user_table table and everything from the jobs table that isn't the userid, but i will need the ability to select multiple things from the 2nd table if needed. so i want to select everything from first table and just certain things from second table.
doesn't work:
SELECT id, i1, i2, i3, i4 FROM jobs, user_table WHERE jobs.id = $id GROUP BY id
doesn't work:
SELECT * from jobs where id = $id UNION SELECT i4 from user_table where userid = $userid
The query
SELECT * FROM jobs
INNER JOIN user_table on jobs.userid = user_table.userid
will join your jobs information with the user information. Then just add your where clause:
SELECT * FROM jobs
INNER JOIN user_table on jobs.userid = user_table.userid
where jobs.id = $id
You want to join the tables like so:
SELECT j.column1, j.column2, u.column5, u.column6
FROM
jobs j
INNER JOIN
user_table u
ON
u.userid = j.userid
WHERE
j.id = $id
try
SELECT id, i1, i2, i3, i4 FROM jobs
inner join user_table on jobs.id = user_table.id WHERE jobs.id = $id GROUP BY id

Join table on multiple ids

exp table: This is where I store entries while keeping the domains and sub domains in a separate table. The sub_domain column can have one or multiple ids that match the id column in misc.
+----+---------+-----------+------------+-----------+--------+-------------+------------+------------+
| id | user_id | job_type | experience | exp_title | domain | sub_domain | start | end |
+----+---------+-----------+------------+-----------+--------+-------------+------------+------------+
| 83 | 268 | Full Time | dasdfg | dest | 76 | 89,91,93,95 | 07/15/2012 | 07/31/2012 |
| 84 | 269 | Full Time | abcdef | title | 77 | 89 | 07/15/2011 | 07/31/2011 |
+----+---------+-----------+------------+-----------+--------+-------------+------------+------------+
misc table:
+-----+----------------------------------------+--------------+
| id | name | category |
+-----+----------------------------------------+--------------+
| 89 | Name1 | category |
| 91 | Name2 | category |
| 93 | Name3 | category |
| 95 | Name4 | category |
| 55 | Name5 | category |
I was wondering how to change LEFT JOIN misc c ON a.sub_domain=c.id if there are more than one sub_domains in the exp table while keeping in mind that there can be one id as well.
$query_str = "SELECT a.*, b.name, c.name AS sub_name
FROM exp a
LEFT JOIN misc b ON a.domain=b.id
LEFT JOIN misc c ON a.sub_domain=c.id
WHERE a.user_id = ?";
It's not good to have columns with comma separated values. Read the answer on the question:
Is storing a comma separated list in a database column really that bad?
Short answer is: It's really that bad.
Until you fix the design, you can use the FIND_IN_SET() function:
$query_str = "
SELECT a.*, b.name, c.name AS sub_name
FROM exp a
LEFT JOIN misc b ON a.domain = b.id
LEFT JOIN misc c ON FIND_IN_SET(c.id, a.sub_domain)
WHERE a.user_id = ?
";
Try this
$query_str =
"SELECT a.*, b.name, c.name AS sub_name
FROM exp a
LEFT JOIN misc b ON a.domain=b.id
LEFT JOIN misc c ON locate(concat('','',c.id ,'',''),'','',a.sub_domain,'','') >0
WHERE a.user_id = ?";
You'd have to do this in two queries. One of the main reasons is that if ever you manage to accomplish what you want to do, you'd be returning rows with practically the same data except for the sub_name column. That's really unnecessary.
You can first JOIN the two tables on a.domain = b.id and then construct a second query that uses an IN(...) statement for all the subdomain values. It'd be something like this:
$subdomains = explode(',', $data_from_first_query['sub_domain']);
if (count($subdomains)) {
$q2 = '
SELECT
b.name
FROM
misc AS b
WHERE b.id IN ('.implode(',',array_fill(0, count($subdomains), '?')).')';
}
Then use foreach to bind values in your placeholder.
But then again, it is good practice to make sure your database is normalized.

Categories