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.
Related
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)
;
I work with PHP and PDO.
So I have 2 tables like,
Table 1
| id | name | age |
| 1 | John | 25 |
| 2 | Tom | 32 |
| 3 | James| 45 |
Table 2
| id | Comment | Link |
| 1 | some text | 3 |
| 2 | some text | 3 |
| 3 | some text | 1 |
So, Link column numbers represent id's in table1. For example Link = 3s in table 2 represent James in table 1. I need a query which brings all table1's data and also a number of repeated value for related Link column which comes from table2.
For example, the query should give me (let's choose James),
| id | name | age | Value |
| 3 | James | 45 | 2 |
value=2, because there are two 3s in link column which related to James
I tried somethings but got lots of errors.
I think you just need the GROUP BY
SELECT a.id,
a.name,
a.age,
count(*) as value
FROM table1 a
JOIN table2 b ON a.id = b.link
GROUP BY a.id, a.name, a.age
If you really want just one row then add WHERE
SELECT a.id,
a.name,
a.age,
count(*) as value
FROM table1 a
JOIN table2 b ON a.id = b.link
WHERE a.name = 'James'
GROUP BY a.id, a.name, a.age
or use subquery
SELECT a.id,
a.name,
a.age,
(SELECT count(*) FROM table2 b WHERE a.id = b.link) as value
FROM table1 a
WHERE a.name = 'James'
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
....
....
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)
I'm having a lot of difficulties in manipulating information in order to achieve the desired result. Through a query I join with the following result:
Area | ID_AT | AT | TYPE
-----------------------------------------
Informatica | 1 | Sistemaa | E
Informatica | 3 | engraçado | E
Informatica | 3 | engraçado | I
Gestão | 2 | aaaaa | I
query:
select a.Area, c.ID_AT, c.AT, dest.type
from AREA_AT a
left join AT_C c on a.id_AREA_AT = c.id_AREA_AT
left join dest_atv d on d.id_AT = c.id_at and d.id_uo = c.id_uo
left join CLIE dest on d.id_CLIE = dest.id_CLIE
where id.uo = 1222
order by a.id_AREA_AT, c.id_at, dest.type
But what I want is to create a table in php as follows:
Area | ID_AT | AT | E | I
-------------------------------------------
Informatica | 1 | Sistemaa | X |
Informatica | 3 | engraçado | X | X
Gestão | 2 | aaaaa | | X
In short, what I intend to do here is to show only one table ID ativ, showing that may exist or not type I or E depending on what comes from the query.
Do I have to modify the query to facilitate the work myself? Or will I have to create a fairly complicated algorithm in php to perform this function? Ando here turns hours and still could not find a solution that will can help me?
It sounds like you need to do a pivot query. Something like
select a.Area,
c.ID_AT,
c.AT,
max( case when dest.type = 'E' then 'X' else null end) E,
max( case when dest.type = 'I' then 'X' else null end) I
from AREA_AT a
left join AT_C c on a.id_AREA_AT = c.id_AREA_AT
left join dest_atv d on d.id_AT = c.id_at and d.id_uo = c.id_uo
left join CLIE dest on d.id_CLIE = dest.id_CLIE
where id.uo = 1222
group by a.area, c.id_at, c.at
order by a.area, c.id_at
Note that you won't be able to ORDER BY the a.id_area_at column if you are not selecting (and grouping by) that column in this formulation. I changed that to sort by a.area instead.