I am creating a CRM for myself. My database contains four tables. In a section of my site I want to while loop all [note] and [task] that are connected to a [contact].
[link] (Linking contact to task)
'id' 'contact_id' 'task_id'
'1' '1' '1'
[contact]
'id' 'contact_name'
'1' 'Robert'
[task]
'id' 'description' 'due_date'
'1' 'Call to say hello' '2016:06:13'
[note] (Note link directly to the contact)
'id' 'contact_id' 'text' 'date_entered'
'1' '1' 'I met Robert on the weekend.' '2016:06:12'
The only way I know at the moment is creating two seperate queries. One to select and display the task information...
$contact_id_for_example = '1'
$find_the_link = $mysqli->query("SELECT * FROM link WHERE contact_id = '$contact_id_for_example'");
if($find_the_link->num_rows != 0){
while($link_rows = $find_the_link->fetch_assoc())
{
$link_task_id = $link_rows['task_id'];
$find_the_task = $mysqli->query("SELECT * FROM task WHERE id = '$link_task_id' ORDER BY due_date");
if($find_the_task->num_rows != 0){
while($task_rows = $find_the_task->fetch_assoc())
{
$task_description = $task_rows['description'];
echo '<li>'.$task_description.'</li>';
}
}
..and one to display the note information..
$note_select = $mysqli->query("SELECT * FROM note WHERE contact_id = '$contact_id_for_example' ORDER BY 'date_entered'");
if($note_select->num_rows != 0){
while($note_rows = $note_select->fetch_assoc())
{
$note_text = $note_rows['text'];
echo '<li>'.$note_text.'</li>';
}
}
The problem with my method is that the above code would print all of the matching tasks first then all of the notes below that. Even if the first note was entered/due well before the task they will always print after the tasks.
I have looked into JOINS and don't see how that would work in this instance due the [link] table interconnecting the [contact] and [task] table.
I have also searched around this site and others and noticed Multiple Queries. but from what I have read so far this doesn't solve the issue either.
Here is my attempt:
$test_contact_id = '1068';
$query = "SELECT * FROM link WHERE contact_id = '$test_contact_id';";
$storing_link = $query->num_rows;
$find_task_id = $storing_link->fetch_fields();
$find_task_id->task_id;
$query .= "SELECT * FROM task WHERE id = '$find_task_id';";
$storing_task = $query->num_rows;
$find_task_description = $storing_task->fetch_fields();
$task_description->text;
$query .= "SELECT * FROM note WHERE contact_id = '$test_contact_id';";
$storing_note = $query->num_rows;
$find_note_text = $storing_note->fetch_fields();
$note_text = $find_note_text->text;
if($mysqli->multi_query($query)){
echo '<p>'.$task_description.' :: '.$note_text.'</p>';
}
JOINs are EXACTLY what you want. You just need a bit of logic to detect when you're moving between record sets. e.g. a simple state machine:
SELECT ...
ORDER BY table1.foo, table2.bar, table3.baz
$prev1 = $prev2 = $prev3 = null;
while($row = fetch()) {
if ($row['table1.foo'] != $prev1) {
start a new table1 output
$prev1 = $row['table1.foo'];
}
... repeat for tables 2&3,
... output "core" data
}
Related
I am having problems achieving the query to select data from a table in the db after a defined value has been met.
My code to do this is:
$fi = 'first_segment'
$im = popo.jpg
$sqls = "SELECT * FROM $fi,news_pictures
WHERE $fi.pi_id = news_pictures.pi_id
AND news_pictures.i_name = '$im'
GROUP BY news_pictures.id DESC";
I wasn't able to achieve the result with that query.
Basically, I want the query to confirm if news_pictures.i_name = '$im' and if true, return starts from the value of $im followed by other data in the table depending on news_pictures.id DESC.
The sample data and output:
Table news_pictures:
id i_name
-- ------
1 coco.jpg
2 lolo.jpg
3 popo.jpg
4 dodo.jpg
Since $im = popo.jpg, I want my query to display all values starting from popo.jpg with id DESC, i.e. popo.jpg, lolo.jpg, coco.jpg.
I got to solve the question with the help of a friend.
$fsqls = "SELECT * FROM $fi,news_pictures WHERE $fi.pi_id = news_pictures.pi_id AND news_pictures.i_name = '$im' GROUP BY news_pictures.id";
$rres = mysqli_query($connection, $fsqls) or print(mysqli_error($connection));
while($row = mysqli_fetch_assoc($rres))
{
$rnm = $row["id"];
}
$sqls = "SELECT * FROM news_pictures WHERE news_pictures.id <= $rnm ORDER BY news_pictures.id DESC";
I am trying to refer the parent query fetched array in sub query of same statement. I have a news table and I want to get a specific news by its title and 10 more news which have id lower than that specific news. I want in one statement of Sql and i am php to fetch array.
<?php
// $_GET['q'] is title
include('db.php');
$result = array();
$sel = "SELECT * FROM news WHERE title = '".$_GET['q']."' "; // AND 10 MORE NEWS WHICH HAVE ID LOWER THAN THIS $_GET['q'] ID .
$qry = #mysqli_query($conn , $sel);
$num = mysqli_num_rows($qry);
while($row = #mysqli_fetch_array($qry)) {
array_push($result, array('id' => $row['id'] , 'title' => $row['title'] , 'desc' => $row['about'] , 'image' => $row['image'] , 'time' => $time , 'htitle' => $row['Htitle'] , 'habout' => $row['Habout']));
}
echo json_encode(array('result' => $result));
?>
Your original query is
SELECT * FROM news WHERE title = :title.
If you really want to use a subquery use something along the lines of
SELECT
*
FROM news
WHERE id <
(SELECT
id
FROM news
WHERE title = :title
LIMIT 1)
ORDER BY id DESC
LIMIT 10
A final note: PLEASE use parameters in your query, because you are WIDE OPEN to SQL injection (think about when $_GET['q'] has a value of ; DROP TABLE news;--).
I have quite a complex question and due to the specifications I've had no luck finding any help with this. Scratching my head for a few months.
I have multiple parameters however in this question I'll focus on only 3
Category ($cat)
Subcategory ($sub)
Genre ($gen)
MySQL columns:
id | category | subcategory | genre | account | date_received | date_modified
(Account is assigned: 1-3)
I would like the results to return:
if only Category is offered:
first the row account = 1, then date_received, followed by date_modified (give no preference to accounts 2 & 3)
if only Category AND Subcategory is offered:
first the row account = 1 and account = 2, then date_received, followed by date_modified (give no preference to account 3)
if only Category AND Subcategory AND genre is offered:
first the row account = 1 and account = 2 and account = 3, then date_received, followed by date_modified
So far I have this:
if ($cat AND empty($sub) AND empty($gen)) {
$run = mysql_query("SELECT *
FROM db
WHERE (category='$cat')
ORDER BY case when account = '1' then 1 else 2 end,
GREATEST(date_received, modified_date, account) DESC ");
} else if ($cat AND $sub AND empty($gen)) {
$run = mysql_query("SELECT *
FROM db
WHERE (category='$cat' AND subcategory='$sub')
ORDER BY case when account = '2' then 1 else 2 end,
GREATEST(date_received, modified_date, account) DESC
");
} else if ($cat AND $sub AND $gen) {
$run = mysql_query("SELECT *
FROM db
WHERE (category='$cat' AND subcategory='$sub' AND genre='$gen')
ORDER BY case when account = '3' then 1 else 2 end,
GREATEST(date_received, modified_date, account) DESC
"); }
Is there an efficient way of combing these and echoing the different results?
It feels really messy.
Many thanks everyone for any tips you can offer.
Put all the conditions in an array, and the preferred account in a variable.
$conds = array();
if ($cat) {
$account = 1;
$conds[] = "category = '$cat'";
}
if ($sub) {
$account = 2;
$conds[] = "subcategory = '$sub'";
}
if ($gen) {
$account = 3;
$conds[] = "genre = '$gen'";
}
if (!empty($conds)) {
$cond_str = implode(' AND ', $conds);
$sql = "SELECT *
FROM db
WHERE $cond_str
ORDER BY IF(account = $account, 1, 2),
GREATEST(date_received, modified_date, account) DESC";
$run = mysql_query($sql);
...
}
I have a table that contains events, to list these events I loop through the event table, check the event type and look up it's value in it's specific table with it's eventId.
At the moment this uses one query to get the 20 events and then up to 3 queries to get the data on those events. I currently have it coded procedurally but need to change it so that at the end it just returns the data in array form.
Here's a Pseduo code example of what I need to achieve:
while(eventQuery):
if commentQueryResult;
$array .= commentQueryResult;
if forumPostQueryResult;
$array .= forumPostQueryResult;
if uploadItemQueryResult;
$array .= uploadItemQueryResult;
endwhile;
return $array; // Combined returned results as one array
I will then be able to access the data and just foreach loop through it.
I'm just not sure the best way to combine multiple result sets into an array?
OR you could try and combine them into one query ...
$eventResult = mysql_query(
'SELECT userevent.event, userevent.eventId, userevent.friendId
FROM userevent
WHERE userevent.userId = 1 OR userevent.friendId = 1
ORDER BY userevent.id DESC
LIMIT 20'
);
while ($eventRow = mysql_fetch_row($eventResult)){
if($eventRow[0] == 1){
$result = mysql_fetch_array(mysql_query("
SELECT forumRooms.id, forumRooms.title
FROM forumPosts
INNER JOIN forumRooms ON forumPosts.`forumTopic` = forumRooms.`id`
WHERE forumPosts.id = '$eventRow[1]'"));
}
elseif($eventRow[0] == 2){
$result = mysql_fetch_array(mysql_query("
SELECT game.id, game.uriTitle, game.title
FROM usergamecomment
INNER JOIN game ON usergamecomment.`gameId` = game.id
WHERE usergamecomment.id = $eventRow[1]"));
}
elseif($eventRow[0] == 4){
$result = mysql_fetch_array(mysql_query("
SELECT usercomment.comment, UNIX_TIMESTAMP(usercomment.TIME), `user`.id, `user`.username, `user`.activate
FROM usercomment
INNER JOIN `user` ON usercomment.`userId` = `user`.id
WHERE usercomment.id = $eventRow[1]
AND `user`.activate = 1"));
}
elseif($eventRow[0] == 5){
$result = mysql_fetch_array(mysql_query("
SELECT game.id, game.title, game.uriTitle
FROM game
WHERE game.id = $eventRow[1]"));
}
// Combined Results as array
}
I'm in the process of converting all of these to PDO, that's the next step after working out the best way to minimise this.
Challenge accepted. ;)
Since you are actually only interested in the results inside the while loop, you could try this single query. Due to the LEFT JOINS it might not be faster, pretty much depends on your database. The final $result contains all elements with their respective fields.
$result = array();
$q = 'SELECT userevent.event AS userevent_event,
userevent.eventId AS userevent_eventId,
userevent.friendId AS userevent_friendId,
forumRooms.id AS forumRooms_id,
forumRooms.title AS forumRooms_title,
game.id AS game_id,
game.uriTitle AS game_uriTitle,
game.title AS game_title,
usercomment.comment AS usercomment_comment,
UNIX_TIMESTAMP(usercomment.TIME) AS usercomment_time,
user.id AS user_id,
user.username AS user_username,
user.activate AS user_activate,
g2.id AS game2_id,
g2.uriTitle AS game2_uriTitle,
g2.title AS game2_title
FROM userevent
LEFT JOIN forumPosts ON forumPosts.id = userevent.eventId
LEFT JOIN forumRooms ON forumPosts.forumTopic = forumRooms.id
LEFT JOIN usergamecomment ON usergamecomment.id = userevent.eventId
LEFT JOIN game ON usergamecomment.gameId = game.id
LEFT JOIN usercomment ON usercomment.id = userevent.eventId
LEFT JOIN user ON usercomment.userId = user.id
LEFT JOIN game g2 ON userevent.eventId = g2.id
WHERE (userevent.userId = 1 OR userevent.friendId = 1)
AND userevent.eventId >= (SELECT userevent.eventId
WHERE userevent.userId = 1 OR userevent.friendId = 1
ORDER BY userevent.id DESC LIMIT 1,20);';
$r = mysql_query($q);
while ( $o = mysql_fetch_row($r) ) {
switch($o['userevent_event']) {
case 1:
$result[] = array(
'id' => $o['forumsRooms_id'],
'title' => $o['forumsRooms_title'],
);
break;
case 2:
$result[] = array(
'id' => $o['game_id'],
'uriTitle' => $o['game_uriTitle'],
'title' => $o['game_title'],
);
break;
case 4:
$result[] = array(
'comment' => $o['usercomment_comment'],
'time' => $o['usercomment_time'],
'id' => $o['user_id'],
'username' => $o['user_username'],
'activate' => $o['user_activate'],
);
break;
case 5:
$result[] = array(
'id' => $o['game2_id'],
'uriTitle' => $o['game2_uriTitle'],
'title' => $o['game2_title'],
);
break;
}
}
Note: Eventually, the query has to be edited slightly, I just wrote that out of my head w/o testing. Optimization can surely be done if I'd knew more about the db structure.
Also, this is merely a proof of concept that it can indeed be done with a single query. ;)
I have a table containing 4 articles with id 1,2,3 and 4 as well as ordering value 1,2,3,4.
They have separate columns for their title, image etc. I need to get them distinctly with where clause. So i did:
For article 1:
//topstory1
$sql_topstory1 ="SELECT * FROM topstory WHERE story_active='1' && story_order='1'";
$result_topstory1 = mysql_query($sql_topstory1);
$row_topstory1 = mysql_fetch_array($result_topstory1);
$story1_title = $row_topstory1['story_title'];
$story1_abstract = $row_topstory1['story_text'];
And for article 2
//topstory2
$sql_topstory2 ="SELECT * FROM topstory WHERE story_active='1' && story_order='2'";
$result_topstory2 = mysql_query($sql_topstory2);
$row_topstory2 = mysql_fetch_array($result_topstory2);
$story2_title = $row_topstory2['story_title'];
$story2_abstract = $row_topstory2['story_text'];
As I have to reuse them in a page.
PROBLEM IS, the first query works but the second one doesn't. It seems like MySql cannot execute two consecutive queries on the same table in a single php file. But I think there is a simple solution to this...
Please help me soon :( Love you guys :)
There are several possible reasons for the second query to fail, but the fact that it's the second query in the file does not cause it to fail.
I would expect that article 2 does not have the active flag set to 1, causing you to get an empty result set.
Another option is that you may have closed the mysql connection after the first query, then you can't execute another query. (General rule: don't close database connections. PHP takes care of that.)
Why not just get them both with 1 query?
$sql_topstory ="SELECT * FROM topstory WHERE story_active='1' && story_order IN(1, 2) ORDER BY story_order DESC";
$result_topstory = mysql_query($sql_topstory) or trigger_error('Query Failed: ' . mysql_error());
while ($row = mysql_fetch_assoc($result_topstory)) {
$title[] = $row['story_title'];
$abstract[] = $row['story_abstract'];
}
// Then to display
echo 'Story 1 is ' . $title[0] . ' with an abstract of ' . $abstract[1];
There are plenty of ways to do this, this is just a simple demonstration.
$query = <<<SQL
SELECT
story_title
, story_text
FROM
topstory
WHERE
story_active
ORDER BY
story_order ASC
SQL;
$result = mysql_query($query);
$stories = array();
while ($row = mysql_fetch_assoc($result)) {
$stories[] = $row;
}
Now you have an array of stories like so:
array(
0 => array(
'story_title' => ?
, 'story_text' => ?
)
, 1 => array(
'story_title' => ?
, 'story_text' => ?
)
)
Should be pretty easy to iterate through.