Trouble understanding how to JOIN mySQL tables properly
Ok here is my problem. I'm adding a table to a existing database to store project notes.
"worklog" is the table with the projects "worklognotes" is the table with the project notes
The notes will be displayed like a discussion thread. worklognotes columns are set up like this id, worklog_id, timestamp, notes.
"id" is the table Unique id. "worklog_id" is the id of the project the no开发者_如何学Pythonte is pretaining to that is stored in another table. "timestamp" is well a Timestamp "notes" are the actual ongoing notes about the project. There could be many notes to a single project.
Looking at the database query below. I have joined the two queries "It's my first join so I'm not sure I've done it right." It is reading the information in both tables and displaying it. But the below code is displaying every entry in "worklog" that has a record in the "worklognotes" table. I need it to display one entry from "worklog" and many notes from "worklognotes"
Can you help or suggest a direction?
$connection = mysql_connect ("localhost", "user", "pass") or die ("I cannot connect to the database.");
$db = mysql_select_db ("database", $connection) or die (mysql_error());
$query = "SELECT * FROM worklog ";
$query .= "JOIN worklognotes ON worklog_id = worklognotes.worklog_id ";
$query .= "WHERE worklognotes.worklog_id=worklog.id ORDER BY worklognotes.id DESC";
Your query to create the JOIN looks correct, but your where clause is redundant. Try this:
SELECT *
FROM worklog
JOIN worklognotes ON worklog_id = worklognotes.worklog_id
ORDER BY worklognotes.id DESC
However for your specific requirements (fetching one record from one table and multiple records from another) there doesn't seem to be a need to join. I think it is best to run two separate queries, otherwise you will get all the data from the first table repeated in every row in your result set.
You'd most likely want:
SELECT *
FROM worklog
LEFT JOIN worklognotes ON worklog_id = worklognotes.worklog_id
WHERE worklog_id = $worklog_id
ORDER BY worklognotes.timestamp DESC;
This will pull out only the work log which has the id stored in $worklog_id (say, 57), and any/all associated worklog notes, displayed newest first.
You query was pulling out ALL worklogs and ALL worklognotes, since you didn't specify exactly which worklog you want, just that they had to have a worklognote.
That is how a join works. You will get one row for each valid combination. The closest you can get to what you want is agregating all worknotes.
SELECT workitem.workID, GROUP_CONCAT( worknotes.note )
FROM `workitem`
JOIN worknotes ON worknotes.workID = workitem.workID
GROUP BY workID
This will give you just one row per workitem and all notes concatinated and seperated with ,
Depending on your column names you may be able to simplify you query with a ntural join:
SELECT workID, GROUP_CONCAT( worknotes.note )
FROM `workitem`
NATURAL JOIN worknotes
GROUP BY `workID`
Natural join is not standart sql but it is a very handy tool. If there is EXACTLY ONE colum that the two tables have in common it will join them just as a inner join with a where clause.
If you want to use another seperator:
SELECT workID, GROUP_CONCAT( worknotes.note SEPARATOR '; ')
FROM `workitem`
NATURAL JOIN worknotes
GROUP BY `workID`
Details on GROUP_CONCAT:
http://dev.mysql.com/doc/refman/5.0/en/group-by-functions.html#function_group-concat
Looking at the database query below. I have joined the two queries "It's my first join so I'm not sure I've done it right." It is reading the information in both tables and displaying it. But the below code is displaying every entry in "worklog" that has a record in the "worklognotes" table. I need it to display one entry from "worklog" and many notes from "worklognotes"
Yes, thats how it works when you join. Youre going to get the worklog entry and a worklognotes entry as a single row. This means youre going to have the same worklog entry multiple times unless it only has one worklognote. You need to sort this out on the php side if you want display in some kind of hierarchy.
So if you want all worklogs (or more than jsut one really) and their notes you would use the query you have and then iterate over the results to organize then appropriately for example assume $result
is your mysql_result resource and $worklog_columns
and $worklognote_columns
contain an array of the columns names for each table in the format 'column_name' => null
then you might do something like the following:
$worklog = array();
while(false !== ($record = mysql_fetch_assoc($result))){
// get only the data for a worklognote
$note = array(array_intersect_key($result, $worklognote_columns));
// get the primary key of the worklog
$id = $record['worklog_id'];
if(!isset($worklog[$id])){
// if we havent already processed this worklog form a previous row
// get the work log data in a separate array
$log = array_intersect_key($result, $worklog_columns);
// add a notes key which will hold an array of worklog_notes
// and assifn the note joined to this row as the first note
$log['notes'] = array($note);
}
else
{
// otherwise jsut append the not joined to this row
// to the existing worklog we processed
$worklog[$id]['notes'][] = $note;
}
}
However the thing you have to be aware of is that if the two tables youre joining have columns with the same name, then if you use MYSQL_ASSOC you will only get the value from the column on the joined table, not from both. IF you need access to the value on both tables then you either need to use MYSQL_NUM or MYSQL_BOTH or alias every column in your query.
精彩评论