In PHP, I use a lot of one liners like:
Fetch value:
$sql->query("SELECT ID FROM table WHERE condition = 1")->fetch_object()->ID;
Fetch row:
$sql->query("SELECT * FROM table WHERE condition = 1")->fetch_assoc();
Fetch rows:
$sql->query("SELECT * FROM table WHERE condition > 1")->fetch_all(MYSQLI_ASSOC);
Insert row:
$sql->query("INSERT INTO table(`row1`,`row2`) VALUES('".$data1."','".$data2."')");
Delete row:
$sql->query("DELETE FROM table WHERE condition = 1");
Are there also beautiful one liners for prepared statements?
This fails:
$sql->prepare("SELECT ID FROM table WHERE condition = ?")->bind_param("i", $a=1)->execute()->fetch_object()->ID;
This works:
$query = $sql->prepare("SELECT ID FROM table WHERE condition = ?");
$query->bind_param("i", $a=1);
$query->execute();
$query->get_result()->fetch_object()->ID;
Directly - there is no way. But you may use a simple overlay class which will allow you to do so.
class PrepareOverlay {
private $stmt;
private $lastResult = null;
public function __construct(PDOStatement $stmt) {
$this->stmt = $stmt;
}
public function __call($name, $arguments) {
$this->lastResult = call_user_func_array([$this->stmt, $name], $arguments);
return is_bool($this->lastResult) ? $this : $this->lastResult;
}
public function getLastResult() {
return $this->lastResult;
}
public static function prepare($sql, $query) {
return new self($sql->prepare($query));
}
}
And use it like this:
PrepareOverlay::prepare($sql, 'SELECT * FROM table WHERE cond = ?')->bindParam('i', $a=1)->execute()->fetchObject()->ID;
Although you will need some phpdoc to make code completion work.
if you consider using a framework like codeigniter you will be able to enjoy the Active record class, and you will be able to use something elegant like those lines :
$query = $this->db->get('mytable');
// Produces: SELECT * FROM mytable
or
$query = $this->db->get_where('mytable', array('id' => $id), $limit, $offset);
or
$this->db->select('*');
$this->db->from('blogs');
$this->db->join('comments', 'comments.id = blogs.id');
$query = $this->db->get();
// Produces:
// SELECT * FROM blogs
// JOIN comments ON comments.id = blogs.id
you can also use chaining like this
$this->db->select('title')->from('mytable')->where('id', $id)->limit(10, 20);
$query = $this->db->get();
or
echo $this->db->count_all('my_table');
// Produces an integer, like 25
or
$this->db->delete('mytable', array('id' => $id));
// Produces:
// DELETE FROM mytable
// WHERE id = $id
and much more ... take a look at the documentation for a full documentation about active record
cheers !
Related
I am new in oop and I am trying to change a sql query into 3 chained method and use like this:
$mtag = $mtag->allTags()->orderBy()->lastThree();
public function allTags()
{
$sql = "SELECT tag_id FROM posts_tags ";
$sql .= "GROUP BY tag_id ";
$sql .= "ORDER BY COUNT(*) DESC LIMIT 3 ";
$res = self::builder($sql);
return $res;
}
i want to use each $sql in to a separate chain method .
how can i do this?
i have tried this but it doesnt work
public function allTags()
{
$sql = "SELECT tag_id FROM posts_tags ";
self::builder($sql);
return $this;
}
public function orderBy()
{
$sql = "GROUP BY tag_id ";
self::builder($sql);
return $this;
}
public function lastThree()
{
$sql = "ORDER BY COUNT(*) DESC LIMIT 3 ";
self::builder($sql);
return $this;
}
my builder method looks like this
public function builder(string $sql)
{
$stmt = $this->database->prepare($sql);
$stmt->execute();
if (!$stmt) {
throw new Exception("Query failed . . .");
}
return $stmt;
}
The problem is that the self::builder($sql); method directly prepares the sql statement, instead of waiting for it to be completely constructed:
$mtag = $mtag
/*
the first self::builder($sql) is called,
prepares the statement without the order and group by
*/
->allTags()
/*
the second self::builder($sql) is called from orderBy, prepares "GROUP BY tag_id "
probably a syntax error is hidden here
*/
->orderBy()
/*
the third self::builder($sql) is called from lastThree
it tries to prepare "ORDER BY COUNT(*) DESC LIMIT 3 "
a syntax error is probably hidden here too
*/
->lastThree();
The statement is prepared over and over again. You can avoid this by doing, in that order
defining the statement with all its chained variants
calling a method to fetch data, preparing the statement composed from the various chained method calls.
$stmt = $mtag->allTags()->orderBy()->lastThree();
$result = $stmt->resolve();
where $stmt = $this->database->prepare($sql); only happens in the resolve method.
you have error in return code.
Change to that code!
public function lastThree()
{
$sql = "ORDER BY COUNT(*) DESC LIMIT 3 ";
$res = self::builder($sql);
return $res;
}
How I use order by (name) in this code to get result in asc order?
This is the piece of code:
function getRecordByID($id)
{
$this->db->select($this->tbl_area_menu.'.*,'.$this->tbl_users.'.firstname as created_by,'.$this->tbl_page.'.name as page_name,'.$this->tbl_page.'.slug as page_slug,'.$this->tbl_page.'.template_directory,'.$this->tbl_directory.'.slug as directory_slug');
$this->db->where($this->tbl_area_menu.'.id',$id);
$this->db->join($this->tbl_users,$this->tbl_users.'.id = '.$this->tbl_area_menu.'.created_by','left');
$this->db->join($this->tbl_page,$this->tbl_page.'.id = '.$this->tbl_area_menu.'.page_id','left');
$this->db->join($this->tbl_directory,$this->tbl_directory.'.id = '.$this->tbl_page.'.template_directory','left');
$query = $this->db->get($this->tbl_area_menu);
//echo $this->db->last_query();
$record = $query->row();
return $record;
}
Looks like you are using Query Builder. If that is the case, after all the joins add $this->db->order_by('name', 'ASC');
Hi have a function that gets passed strings via the below;
getFilterResults($id, $limit, $misc);
and in my function i connect to SQLite DB and build a query based on the values passed through, like so;
function getFilterResults($id, $limit, $misc) {
$dbConnect = new SQLite3(database);
if(!empty($limit) && !empty($id) && !empty($misc)){
$buildString = ('SELECT * FROM fields ORDER BY id DESC');
}else{
//no params filters arrived so dont filter - aka get all results
$buildString = ("SELECT * FROM fields ORDER BY id DESC");
}
$query = $dbConnect->query($buildString);
//...
}
Issue is how do I build the query if some of the values are empty and I have to decide which value uses/starts of the 'WHERE' query..obviously the first value return that is not null starts of the 'WHERE'..
I can see the long way would be to loop through each one and build - once the first value found that is not null and kick off from there but that seems unpractical and not good practice.
//check if limit set..
if($limit) {
$doLimit = 'LIMIT '.$limit.'';
}
WHERE 'id = '.id.' AND misc = '.$misc.' '.$doLimit.'
Your function taking in ($id, $limit, $misc) really prevents you from being able to do anything else than what you already are... I would recommend using prepared statements though
// Stores values for a prepared statement
$values = [];
$sqlite = new SQLite3(/* ... */);
$query = 'SELECT * FROM fields WHERE id = ? AND misc = ? ORDER BY id DESC';
$values[] = $id;
$values[] = $misc;
if ($limit) {
$query .= ' LIMIT ?';
$values[] = $limit;
}
// Use prepare and let SQLite3 escape the values for you
$stmt = $sqlite->prepare($query);
foreach ($values as $idx => $val) {
$stmt->bindValue($idx, $val);
}
$result = $stmt->execute();
Just want to get user_id and review_text values from table reviews, select name and city from table users where id=user_id and then return review_text, username and city to controller. Please help me.
public function did_get_reviews($item_id){
$this->db->select('user_id','review_text');
$this->db->from('reviews');
$this->db->where('post_id', $item_id);
$user_id = 'user_id' //??
$this->db->select('name','city');
$this->db->from('users');
$this->db->where('id', $user_id);
$query = $this->db->get('review_text','username','city'); //??
if ($query && $query->num_rows() >= 1){
return $query->result();
}
else {
return false;
}
}
Update 1:
I just tried to join tables but it returns the values for review_text only but I also want to get values for name and city. Please check the code below:
public function did_get_reviews($item_id){
$this->db->select('reviews.review_text','users.name','users.city');
$this->db->from('reviews','users');
$this->db->where('reviews.post_id', $item_id);
$this->db->join('users','reviews.user_id = users.user_id');
$query = $this->db->get();
if ($query && $query->num_rows() >= 1){
return $query->result();
}
else {
return false;
}
}
i think you need to use join query in SQL. if you use this code you can access to what you want
$result = $this->db->select('review, username, city')
->from('reviews')
->join('city', 'city.user_id = review.user_id')
->get();
print_r($result);
for more information about how you can write join query(left, inner or right) in codeigniter you can see this link
i hope that this code solve your problem
UPDATE
in your new question. your code have a little buggy. you need to write your select in this way
public function did_get_reviews($item_id){
$this->db->select('reviews.review_text,users.name,users.city')
->from('reviews','users')
->where('reviews.post_id', $item_id)
->join('users','reviews.user_id = users.user_id');
$query = $this->db->get();
if ($query && $query->num_rows() >= 1){
return $query->result();
}
else {
return false;
}
}
in codeigniter select Active record; any column name separate with each other by , only (not by ' and ,)
in codeigniter documentation wrote that
Permits you to write the SELECT portion of your query:
$this->db->select('title, content, date');
$query = $this->db->get('mytable');
// Produces: SELECT title, content, date FROM mytable
You can get the value for user_id using:
$this->db->select('user_id','review_text');
$this->db->from('reviews');
$this->db->where('post_id', $item_id);
$result = $this->db->get();
print_r($result);
use the same $this->db->get(); to get the values of the second query as well. Once you get the values inside a variable you can iterate it. Something like:
foreach ($result->result() as $row)
{
echo $row->name;
echo $row->city;
}
I have a query that is working but is does not have binded values:
$this->_db->query("SELECT * from posts WHERE post_title LIKE '%$this->search_keywords%' OR post_content LIKE '%$this->search_keywords%' LIMIT 100");
$this->rows_results_found = $this->_db->resultset();
$this->results_found_num = sizeof($this->rows_results_found);
I am rewriting it to this one but with no luck:
$this->_db->query('SELECT * from posts WHERE post_title LIKE :search_keywords OR post_content LIKE :search_keywords LIMIT 100');
$this->_db->bind(':search_keywords', '%$this->search_keywords%');
$this->rows_results_found = $this->_db->resultset();
$this->results_found_num = sizeof($this->rows_results_found);
$this->results_found_num appears always to be an empty array.
This is what I have in the resultset() (It is from another outer class):
public function resultset() {
$this->execute();
return $this->stmt->fetchAll(PDO::FETCH_ASSOC);
}
What I am missing here?
Thank you in advance!
Assuming you have a valid connection adjust your function to the following:
public function get_posts($conn) {
$query = 'SELECT *
FROM posts
WHERE post_title LIKE :search_keywords1 OR
post_content LIKE :search_keywords2 LIMIT 100';
$stmt = $conn->prepare($query);
$stmt->bindValue(':search_keywords1', '%'.$this->search_keywords.'%');
$stmt->bindValue(':search_keywords2', '%'.$this->search_keywords.'%');
$stmt->execute();
return $stmt->fetchAll(PDO::FETCH_ASSOC);
}
Usage:
$posts = $this->_db->get_posts($conn);
//var_dump($post)
$this->rows_results_found = count($post);