PHP: Active record table joins - php

I have an app that uses the codeigniter CXTags tagging library.
The database structure is as follows:
posts
id
tags_ref
row_id
table
tag_id
tags
id
safe_tag
tag
My query basically goes if $safe_tag is not null then join tags_ref on post.id = tags_ref.row_id, join tags on tags_ref.tag_id = tags.id, where tags_ref.table = 'posts' and tags.safe_tag = 'food'
SELECT * FROM posts
JOIN tags_ref ON posts.id = tags_ref.row_id
JOIN tags ON tags_ref.tag_id = tags.id
WHERE tags.safe_tag = $safe_id
Unfortunately the query I've written in active record is not functioning properly. The query works perfectly when £safe_tag is null but when it's not I get wrong results.
function get_posts($id = NULL, $safe_tag = NULL) {
if($safe_tag != NULL){
echo $safe_tag;//debugging
$table = 'posts';
$this->db->join('tags_ref', 'posts.id = tags_ref.row_id');
$this->db->join('tags', 'tags_ref.tag_id = tags.id');
$this->db->where('tags_ref.table', $table);
$this->db->where('tags.safe_tag',$safe_tag);
}
//if an id was supplied
if ( $id != NULL ) {
$this->db->where('posts.city_id',$id);
}
// execute query
$query = $this->db->get('posts');
...
Here is the query with profiling on:
SELECT *
FROM (`posts`)
INNER JOIN `tags_ref` ON `posts`.`id` = `tags_ref`.`row_id`
INNER JOIN `tags` ON `tags_ref`.`tag_id` = `tags`.`id`
WHERE `tags_ref`.`table` = 'posts'
AND `tags`.`safe_tag` = 'food'
AND `posts`.`city_id` = '2'
Can someone have a look? I think I need a fresh set of eyes on it.

Your forgot to actually run the query inside your first if{}
if($safe_tag != NULL){
echo $safe_tag;//debugging
$table = 'posts';
$this->db->join('tags_ref', 'posts.id = tags_ref.row_id');
$this->db->join('tags', 'tags_ref.tag_id = tags.id');
$this->db->where('tags_ref.table', $table);
$this->db->where('tags.safe_tag',$safe_tag);
$this->db->get(); // here
}

Related

How to add where not equal to in Query [duplicate]

This question already has answers here:
When to use single quotes, double quotes, and backticks in MySQL
(13 answers)
Closed 3 years ago.
I'm trying to add a condition as active is not qual to 1, but I can't figure it out how it's working correctly in my query.
Here is my query
$career_solutions_data = DB::select("
SELECT
career_solutions.id,
role_users.role_id,
career_solutions.user_id,
career_solutions.subject,
career_solutions.date,
career_solutions.public,
career_solutions.views,
career_solutions.optional,
career_solutions.on_offer,
career_solutions.active,
users.username,
users.profile_picture,
categories.category,
categories.category_url,
categories.color,
career_solutions_categories.category as sub_category,
career_solutions_format.category as event_format,
career_solutions_certification.category as certification
FROM career_solutions
INNER JOIN categories
ON categories.id = career_solutions.topic_category_id
INNER JOIN career_solutions_format
ON career_solutions_format.id = career_solutions.topic_format_id
INNER JOIN career_solutions_certification
ON career_solutions_certification.id = career_solutions.topic_certification_id
INNER JOIN career_solutions_categories
ON career_solutions_categories.id = career_solutions.topic_subcategory_id
INNER JOIN users
ON users.id = career_solutions.user_id
LEFT JOIN role_users on role_users.role_id = users.id
INNER JOIN privacy_settings
ON privacy_settings.user_id = users.id
WHERE users.deleted_at IS NULL
AND (
(privacy_settings.career_solutions = 0 AND public = 1 )
OR (users.id IN (
SELECT contacts.contact_id
FROM contacts
WHERE contacts.user_id = $id
)
)
)
OR users.id = $id
ORDER BY date desc limit 5000
");
$role = User::with('role')
->where ('id', '=', $id)
->first();
// $career_solutions_data;
foreach ($career_solutions_data as $career_solution)
{
preg_match('/<img.+src=[\'"](?P<src>.+?)[\'"].*>/i', $career_solution->optional, $image);
if(isset($image['src']))
{
$type_picture = $image['src'];
}
else{
$type_picture = "";
}
$temp_soluation = array();
$temp_soluation['type'] = 'Career Solution';
$temp_soluation['typee'] = 'briefcase';
$temp_soluation['subject'] = $career_solution->subject;
$temp_soluation['information'] = $career_solution->optional;
$temp_soluation['category'] = $career_solution->category;
$temp_soluation['category_url'] = $career_solution->category_url;
$temp_soluation['color'] = $career_solution->color;
$temp_soluation['all_url'] = 'search-career-solutions';
$temp_soluation['type_url'] = 'view-career-solutions';
$temp_soluation['id'] = $career_solution->id;
$temp_soluation['date'] = $career_solution->date;
$temp_soluation['public'] = $career_solution->public;
$temp_soluation['active'] = $career_solution->active;
$temp_soluation['sub_category'] = $career_solution->sub_category;
$temp_soluation['event_format'] = $career_solution->event_format;
$temp_soluation['certification'] = $career_solution->certification;
$temp_soluation['on_offer'] = $career_solution->on_offer;
$temp_soluation['username'] = $career_solution->username;
$temp_soluation['roleMe'] = $career_solution->optional;
$temp_soluation['role'] = $role->role[0]->id;
$temp_soluation['profile_picture'] = $career_solution->profile_picture;
$temp_soluation['type_picture'] = $type_picture;
// $news_events_opinions[] = $temp_soluation;
$my_career_solution[] = $temp_soluation;
}
}
This is what I have tried to add :
WHERE `career_solutions.active` <> `1`
or
WHERE `active` <> `1`
or
WHERE `active` != `1`
but didn't working.So, I need to not displaying the posts with active = 1.I have another 3 queries, different of that, where I have used this : ->where("active","!=",1);, but here I can't use it.
The problem are the backticks around the 1: This instructs MySQL to search for a column name 1.
Try WHERE career_solutions.active <> 1

mysqli - Delete method not deleting

Got a delete method which is not working ... can anybody figure out why it's returning 0? The item is present in the table.
public function deleteItem($item_id)
{
$userItemIDS = array();
$userItemIDS = $this->helperClass->userItemIDS();
if( !in_array($item_id, $userItemIDS) )
{
return false;
}
$q = $this->db->mysqli->prepare("DELETE i, s FROM items i
LEFT JOIN save_list s
ON i.id = s.item_id
WHERE i.id = ? AND s.item_id = ?
AND
NOT EXISTS (SELECT id FROM pending_wins WHERE item_id = ?)
AND
NOT EXISTS (SELECT id FROM bids WHERE item_id = ?)");
if($q)
{
$q->bind_param("iiii", $item_id, $item_id, $item_id, $item_id);
$a_r = $q->affected_rows;
$q->execute();
$q->close();
return $a_r;
}
}
The comments are very helpful and I appreciate them a lot. However my problem was in the query itself. Taking out AND s.item_id = ? deletes the
entry from the items table and fromsave_list if present.
$q = $this->db->mysqli->prepare("DELETE i, s FROM items i
LEFT JOIN save_list s
ON i.id = s.item_id
WHERE i.id = ?
AND
NOT EXISTS (SELECT id FROM pending_wins WHERE item_id = ?)
AND
NOT EXISTS (SELECT id FROM bids WHERE item_id = ?)");

f3 framework sql query join

I have the following tables:
tbl_users
===============
uid
username
password
gid
tbl_groups
===============
gid
name
type
I am trying to figure out how to use the sqlmapper in f3 to be able to query both tables where username equals $_POST["username"] and be able to get the group name and type as well. Is it possible to join like queries using this framework with sqlmapper?
I've been searching around and can't find any examples on that.
you can try to setup some virtual fields for this:
$mapper->group_name = 'select name from tbl_groups where tbl_groups.gid=tbl_users.gid';
$mapper->group_type = 'select type from tbl_groups where tbl_groups.gid=tbl_users.gid';
$mapper->load(array('uid = ?',123));
echo $mapper->group_name;
Here is the example with {VIEW}:
I have implemented here pagination with SQL Mapper using View view_user_list_with_referral
$dropInstantWinnerView = $this->db->exec("DROP VIEW IF EXISTS view_user_list_with_referral;");
$createInstantWinnerView = $this->db->exec("CREATE VIEW view_user_list_with_referral AS SELECT u.fb_id, fb_link, name, r.referred_by, u.created FROM users u LEFT OUTER JOIN referral r ON u.fb_id=r.joinee ");
$user = new \DB\SQL\Mapper($this->db,'view_user_list_with_referral');
$limit = 20;
$page = Pagination::findCurrentPage();
$order_condition = F3::get("PARAMS.order_condition");
$order_class= "";
if(!empty($order_condition)){
$cond = explode(":", $order_condition);
$option = array('order' => $cond[0].' '.$cond[1]);
if($cond[1]=='ASC'){
$order_condition = $cond[0].':DESC';
$order_class = ":DESC";
}else{
$order_condition = $cond[0].':ASC';
$order_class = ":ASC";
}
}else{
$option = array('order' => 'created DESC');
}
$subset = $user->paginate($page-1, $limit, null, $option);
$pages = new Pagination($subset['total'], $limit);
$pages->setTemplate("admin/pagebrowser.html");
F3::set('pagebrowser', $pages->serve());
//echo "<pre>";print_r($subset);exit;
F3::set('page', $page);
F3::set('order_condition', $order_condition);
F3::set('total_found_records', $user->count());
I hope it will save someones time :)

Arranging JOIN database results

I am currently getting details from my 'social_posts' table, and then adding it's tags, the number of likes, and the number of answers it has to the resulting object. Is there a way I can be doing this without having to do extra queries in a loop?
$query = "SELECT * FROM social_posts JOIN users ON social_posts.user_id = users.id";
$posts = $this->db->query($query);
if ($posts->num_rows() > 0) {
foreach ($posts->result() as $p => $post) {
// Get the question's tags
$tags = $this->db->query("SELECT * FROM social_tags
WHERE post_id = ?", $post->post_id);
// Get the number of likes
$likes = $this->db->query("SELECT id FROM social_likes
WHERE post_id = ?", $post->post_id);
// Get the number of answers
$answers = $this->db->query("SELECT id FROM social_responses
WHERE post_id = ?", $post->post_id);
$post->tags = $tags->result();
$post->likes = $likes->num_rows();
$post->answers = $answers->num_rows();
$post->author = array(
"firstname" => $post->firstname,
"thumbnail" => $post->thumbnail,
);
}
return $posts->result();
} else {
return FALSE;
}
You may try this SQL:
SELECT
social_posts.*,
users.*,
GROUP_CONCAT(social_tags.name) AS tags,
COUNT(social_likes.id) AS likes,
COUNT(social_responses.id) AS answers
FROM
social_posts
JOIN users ON social_posts.user_id = users.id
LEFT JOIN social_tags ON social_tags.post_id = social_posts.id
LEFT JOIN social_likes ON social_likes.post_id = social_posts.id
LEFT JOIN social_responses ON social_responses.post_id = social_posts.id
GROUP BY
social_posts.id
You will get the tags as comma delimited string. Of course you need to adjust the column names to fit your database.

Unnexpected item-comments depending on query of items

I am using this function to list items from table helps depending on parameters: (I included most of code but you can really just focus on the mysql querys)
function list_helps($by,$value,$page = -1,$ipp = 20){
/* Yes I concatenate querys... so i use some variables to help it a bit */
$sql = 'SELECT helps.* FROM helps ';
$where = ''; $orderBy = ''; $in = ''; $join = ''; $limit = ''; $resultitems = ''; $header = '';
if($page > 0) $limit = 'LIMIT '.$page*$ipp.', '.($page+1)*$ipp; else $limit = 'LIMIT 10';
switch($by){
case 'byuser':
$where = 'WHERE id_user ='.$value;
$orderBy = 'ORDER BY id DESC';
break;
case 'byfriend':
$sql = 'SELECT
h.*,
f.*
FROM (
SELECT
id,
CASE followerid WHEN '.$value.' THEN followingid ELSE followerid END AS friend_id
FROM friends
WHERE acepted = 1
AND (followerid = '.$value.' OR followingid = '.$value.')
) AS f
INNER JOIN helps AS h ON h.id_user = f.friend_id
ORDER BY h.id DESC';
break;
default:
break;
}
$sql .= $where.' '.$orderBy.' '.$limit;
$res = cache_query($sql,'',60*60*5);
/* checks in cache first, if not; executes query.. next code it's to render content */
}
There are more cases but lets focus on those two.
They both serve the 'helps' that are being requested (if user, or if users's friend); The problem is when i am trying to retrieve the comments of those (like if it where a blog post); which I am doing like so:
res = cache_query('SELECT help_replies.content, help_replies.date,
help_replies.offers, help_replies.accepted, help_replies.id_responds,
usuarios.first_name, usuarios.last_name, usuarios.avatar,usuarios.id
FROM help_replies left join usuarios
ON help_replies.id_user = usuarios.id
WHERE help_replies.id_responds = '.$this->id.'
ORDER BY help_replies.id ASC', '', 30);
foreach($res as $obj) {
/* $obj['id_responds'] */
}
}
The thing is that the help_replies.id_responds makes reference to the item, so when the case is 'byuser' is fine; but when the case is 'byfriend' this field is lost (so is showing always the same comments)
Conclusion:
byuser -> helps fine & comments fine
byfriend -> helps fine (which is wierd) & comments wrong
Any Idea why $this->id is not as expected from the (JOINED) query?
-EDIT-
$this->id comes from this construct method (i ommited many atributes)
function __construct($item) {
$this->id = $item['id'];
$this->id_user = $item['id_user'];
..
}
And $item is one iteration of the foreach (so its the returned row converted to array)
Muchas Gracias
Your byfriends query executed by function list_helps(...) appears to return a field labelled id twice; once for your helps table and then again for f the alias of the friends table, as part of the sub-query.
I can imagine that if $this->id contains a friends id and not the helps id then your comments query (help_replies) will return the wrong results.
So perhaps changing your sub-query with an alias for the friends id as shown ie id AS friendsId, everything will work as expected?
function list_helps($by,$value,$page = -1,$ipp = 20){
...
...
case 'byfriend':
$sql = 'SELECT
h.*,
f.*
FROM (
SELECT
id AS friendsId,
CASE followerid WHEN '.$value.' THEN followingid ELSE followerid END AS friend_id
FROM friends
WHERE acepted = 1
AND (followerid = '.$value.' OR followingid = '.$value.')
) AS f
INNER JOIN helps AS h ON h.id_user = f.friend_id
ORDER BY h.id DESC';
break;
I've got into the habit of naming my table identifier field <tablename>Id for this very reason and saves having to use alias everywhere.

Categories