This is my active record code in CodeIgniter:
$this->db->...
$this->db->join('post_likes', 'post_likes.user_id="'.$this->db->escape($online_user).'" AND post_likes.post_id=post.id', 'left');
And this is how it is interpreted:
LEFT JOIN `post_likes` ON `post_likes`.`user_id`="`3"` AND post_likes.post_id=post.id
it gives the error:
`user_id`="`3"`
How to write a direct number in active record?
Update:
removing escape
to test it on your computer you dont need to have a database. Just trying this code shows the error:
$this->db->select('*')
->from('mytable')
->join('post_likes', 'post_likes.user_id="3" AND post_likes.post_id=post.id', 'left');
$query=$this->db->get('');
var_dump($this->db->last_query());
exit(0);
result:
A Database Error Occurred
Error Number: 1064
You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near '` AND post_likes.post_id=post.id' at line 3
SELECT * FROM (`mytable`) LEFT JOIN `post_likes` ON `post_likes`.`user_id`="`3"` AND post_likes.post_id=post.id
You SHOULD not use the double quotes in SQL query:
$this->db->join('post_likes', "post_likes.user_id = $online_user AND post_likes.post_id=post.id", 'left');
Update:
This is a bug in the current CI stable version (fixed in v3.0-DEV), CI ActiveRecord methods (which doesn't implement really ActiveRecord) are prepared for simple usages.
I fixed this issue before by hacking the core files (by adding a parameter to join method to disable _protect_identifires).
There we go:
In system/database/DB_active_rec.php line #310, add $escape as 4th parameter:
public function join($table, $cond, $type = '', $escape = TRUE)
And change $match[3] = ... to:
if ($escape === TRUE)
{
$match[3] = $this->_protect_identifiers($match[3]);
}
So, you can use join($table, $cond, $type = '', $escape = FALSE) to disable escaping.
In addition, setting _protect_identifires globally to FALSE is not in a correct direction.
the only option remains is using custom query():
$sql = "SELECT * FROM some_table WHERE id = ?"
$this->db->query($sql, array(3));
Try this
$this->db->join('post_likes', "post_likes.user_id=$the_userid AND
post_likes.post_id=post.id", 'left');
or
$this->db->join('post_likes', 'post_likes.user_id="'.$the_userid.'" AND
post_likes.post_id=post.id', 'left');
Update:
Define
$db['default']['_protect_identifiers']= FALSE;
in "application/config/database.php" at the end.
Simple solution would be to temporarily set the protect_identifiers off before join query, like so:
$this->db->_protect_identifiers = false;
After making join query you could set it back to true
Works for me in CodeIgniter version 2.1.2
try this one
$this->db->join('post_likes', 'post_likes.user_id="{$online_user}" AND post_likes.post_id=post.id', 'left');
please let me know if you face any problem.
Dont use $this->db->escape
$this->db->join('post_likes', 'post_likes.user_id="'.$online_user.'" AND post_likes.post_id=post.id', 'left');
Related
I have been working on this for like more than 4 hours. I have select query using active record I am doing: $this->db->like ('items.name',$search);
everything works fine but whenever there is single quote (') in the $search string it gives this error:
You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 's%' OR default_items.short LIKE 'faith\'s%' LIMIT 5' at line 5
I have just checked now that it is adding double back slashes \\ instead of single in my active record for LIKE query. I tried in MySQL bt removing one slash and it is working.
My code:
$q = "faith's";
$query = $this->db->select('items_categories.slug as category_slug, items_categories.name as cat_name, items.name, items.price_value, items.cover_photo, items.slug');
$query->select('default_items.short as short',false);
$query->select('date(default_items.date_created) as date_created',false);
$query->join('items_categories','items_categories.id=items.root_id','inner');
$query->join('users','items.company_id=users.id','inner');
$query->like('items.name',$q);
$query->or_like('items.short',$q);
$query->limit(5);
$result = $query->get($this->_table);
$both_prod_results = $result->result();
I am using pyrocms 2.x.
You can try the following code maybe it can help you, but you have to add \ before every' in your requests :
$value = "faith\'s";
$sql_request = "`short` LIKE '%". $value ."%'";
$query = $this->db
->select('*')
->where($sql_request, null, false)
->get('default_items');
$result = $query->result();
dump($result);
i think i need to answer my own question.
Well this is a hack(don't think if it is secure)
I have patched my MYSQLI Driver:
i have replaced this:
return str_replace(array($this->_like_escape_chr, '%', '_'),
array($this->_like_escape_chr.$this->_like_escape_chr, $this->_like_escape_chr.'%', $this->_like_escape_chr.'_'),
$str);
with this:
return str_replace(array($this->_like_escape_chr, '%', '_'),
array($this->_like_escape_chr, $this->_like_escape_chr.'%', $this->_like_escape_chr.'_'),
$str);
it was adding extra slash. and also don't think it will allow sql injections etc anything.
if anyone knows this is right then please comment.
Thanks
Umair
I am working on codeigniter and I am writing the following query:
$this->db->select('*');
$this->db->from('tbl_profile');
$this->db->join('tbl_msg', 'tbl_msg.msg_sender_id = tbl_profile.profile_id');
$this->db->order_by("msg_id", "desc");
$query = $this->db->get('', $config['per_page'], $this->uri->segment(3));
$data['records'] = $query->result_array();
Correspondingly I am getting the following result:
SELECT (*) FROM tbl_profile
JOIN tbl_msg ON tbl_msg.msg_sender_id = tbl_profile.profile_id
Which is returninng a wrong result as I want the result corresponding to the following query:
select * from tbl_profile as A
join (select * from tbl_msg) as B on A.profile_id = B.msg_sender_id
Please help
First of all, you missing the order by clause, but I assum, you mean other differences.
If you want that, you can use this query, what will gave you back the exact code:
$this->db->select('*', FALSE);
$this->db->from('tbl_profile as A');
$this->db->join('( select * from tbl_msg ) as B', 'A.msg_sender_id = B.profile_id');
$this->db->order_by("msg_id", "desc");
$query = $this->db->get('', $config['per_page'], $this->uri->segment(3));
$data['records'] = $query->result_array();
From codeigniter user manual:
$this->db->select()
accepts an optional second parameter. If you set it to FALSE, CodeIgniter will not try to protect your field or table names with backticks. This is useful if you need a compound select statement.
I have configured code igniter to use db prefix.
At all other places it is working as expected but while creating table aliases it is prepending db prefix.
Code is as under:-
$this->db->from('table_a');
$this->db->join('table_b', 'table_a.id = table_b.a_id', 'left');
-----
$this->db->join('table_b as tablebAlias', 'table_c.id = tablebAlias.a_id', 'left');
Assuming my dbprefix is set to value 'foo'.
Final query which is getting executed is as under:-
Select * From foo_table_a left join foo_table_b on foo_table_a.id = foo_table_b.a_id
--- left join foo_table_b as tablebAlias on foo_table_c.id = foo_tablebAlias.a_id
Any help will be highly appreciable.
Thanks,
Jatin
I found out that manual queries ignore table prefix. I also found out that there is a way to add table prefix to manual queries:
In config/database.php
One can do this:
$db['default']['dbprefix'] = "feed_";
$db['default']['swap_pre'] = "{PRE}";
So that this can be done:
$sql = "SELECT * FROM {PRE}item";
$query = $this->db->query($sql);
The {PRE} becomes feed_.
But swap_pre is not config.php which leads me to think that this is CI 2.0 feature.
I'm trying to do this:
SELECT
userId, count(userId) as counter
FROM
quicklink
GROUP BY
userId
HAVING
count(*) >= 3'
In doctrine with the querybuilder, I've got this:
$query = $this->createQueryBuilder('q')
->select('userId, count(userId) as counter')
->groupby('userId')
->having('counter >= 3')
->getQuery();
return $query->getResult();
Which gives me this error:
[Semantical Error] line 0, col 103 near 'HAVING count(*)': Error: Cannot group by undefined identification variable.
Really struggling with doctrine. :(
Your SQL is valid, Your query builder statement is invalid
All cause db will execute that query in following order:
1. FROM $query = $this->createQueryBuilder('q')
2. GROUP BY ->groupby('userId') // GROUP BY
3. HAVING ->having('counter >= 3')
4. SELECT ->select('userId, count(userId) as counter')
So as You can see counter is defined after its use in having.
Its SQL Quirk. You can not use definitions from select in where or having statements.
So correct code:
$query = $this->createQueryBuilder('q')
->select('userId, count(userId) as counter')
->groupby('userId')
->having('count(userId) >= 3')
->getQuery();
return $query->getResult();
Do note repetition in having from select
I am going to answer for people who still have this type of error.
First things first, you seem to have translated a native sql query inside a query builder object. More so, you have named your object as q
$query = $this->createQueryBuilder('q');
What this means, in general, is that every condition or grouping etc you have in your logic should address fields of q: q.userId, q.gender, ...
So, if you had written your code like below, you would have avoided your error:
$query = $this->createQueryBuilder('q')
->select('q.userId, count(q.userId) as counter')
->groupby('q.userId')
->having('counter >= 3')
->getQuery();
return $query->getResult();
I think you are missing the 'from' statement
$query = "t, count(t.userId) as counter FROM YourBundle:Table t group by t.userId having counter >1 ";
return $this->getEntityManager()->createQuery($query)->getResult();
This should work. You can even do left joins or apply where clausules.
you can define HAVING parameter via setParameter() method as well
$qb->groupBy('userId');
$qb->having('COUNT(*) = :some_count');
$qb->setParameter('some_count', 3);
Previously my all queries were running fine in CI version 2.0 but when I upgraded to 2.0.3 some of my SELECT queries were broken.
CI is adding backticks (``) automatically, but in older version its running as it is.
CI user manual have instructed to add second parameter in
db->select
as
FALSE
but still it's not working.
Code is as following:
class Company_model extends MY_Model
{
----------------
$this->db->select(' count('.$fieldname. ') as num_stations');
$this->db->select(" CONCAT_WS(',', clb_company.address1, clb_company.address2, clb_company.city, clb_company.state, clb_company.zipcode ) as companyAddress");
$this->db->from($this->_table);
$this->db->join($this->_table_device, $fieldname1. " = ". $fieldname2, 'LEFT');
$this->db->where($blablafield , '0');
----------------
The error is as follows:
Error Number: 1064
You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near
'FROM (`clb_device`) JOIN `clb_company` ON `clb_company`.`id` = `clb_device`.`com' at line 2
SELECT `clb_device`.`id` as deviceId, `clb_pricing_specifications`.`name` as pricingSpecName, `clb_company`.`name` as companyName, `clb_device`.`mac_address` as deviceMacAddress,
`clb_device`.`reseller_model_number` as deviceModelNumber, `clb_pricing_spec_grouping`.`pricing_master_spec_id` as pricingSpecId, `clb_device`.`address` as deviceAddress,
`clb_device`.`is_home` as deviceIsHomeCharger, CONCAT(clb_company.portal_line1, `'/'`, `clb_device`.`name)` as deviceDisplayName FROM (`clb_device`) JOIN `clb_company`
ON `clb_company`.`id` = `clb_device`.`company_id` LEFT JOIN `clb_pricing_group_devices` ON `clb_device`.`id` = `clb_pricing_group_devices`.`device_id` and clb_pricing_group_devices.is_active = 1
LEFT JOIN `clb_pricing_spec_grouping` ON `clb_pricing_group_devices`.`pricing_spec_id` = `clb_pricing_spec_grouping`.`pricing_master_spec_id` LEFT JOIN `clb_pricing_specifications` ON
`clb_pricing_spec_grouping`.`pricing_spec_id` = `clb_pricing_specifications`.`id` WHERE clb_company.vendor_id is not null AND cast(substr(clb_devi
ce.software_version, 1, 3) as decimal(2,1)) > 2.0 AND clb_device.device_state > 0 GROUP BY `clb_device`.`id` ORDER BY CONCAT(trim(clb_company.portal_line1), `'/'`, trim(clb_device.name)) desc LIMIT 20
Have a look at CONCAT(trim(clb_company.portal_line1), `'/'`, trim(clb_device.name))
Please suggest the workaround.
Use this line before your query:
$this->db->_protect_identifiers=false;
This will stop adding backticks to the built query.
The solution is very simple:
In the database configuration file (./application/config/database.php) add a new element to array with default settings.
$db['default']['_protect_identifiers']= FALSE;
This solution is working for me and more elegant and professional.
All other answers are really old, this one works with CI 2.1.4
// set this to false so that _protect_identifiers skips escaping:
$this->db->_protect_identifiers = FALSE;
// your order_by line:
$this -> db -> order_by('FIELD ( products.country_id, 2, 0, 1 )');
// important to set this back to TRUE or ALL of your queries from now on will be non-escaped:
$this->db->_protect_identifiers = TRUE;
class Company_model extends MY_Model
{
----------------
$this->db->select(" count('$fieldname') as num_stations",false);
$this->db->select(" CONCAT_WS(',', clb_company.address1, clb_company.address2, clb_company.city, clb_company.state, clb_company.zipcode ) as companyAddress",false);
$this->db->from($this->_table);
$this->db->join($this->_table_device, $fieldname1. " = ". $fieldname2, 'LEFT');
$this->db->where($blablafield , '0');
----------------
The false you were talking about is what is needed, can you try the code above and copy and paste to us the output of
echo $this->db->last_query();
This will show us what the DB class is creating exactly and we can see whats working / what isn't. It may be something else (you haven't given the error from that is generated sometimes sql errors can be misleading.)
From the docs:
$this->db->select() accepts an optional second parameter. If you set it to FALSE, CodeIgniter will not try to protect your field or table names with backticks. This is useful if you need a compound select statement.
CI will only protect your ACTIVE RECORD calls, so if you are running $this->db->query(); you will be fine, and based on the notes you should be safe with AD calls like so to disable backticks (not sure why you say they don't work, but I don't see your full code, so I can't be sure)
$this->db->select('(SELECT SUM(payments.amount) FROM payments WHERE payments.invoice_id=4') AS amount_paid', FALSE);
$query = $this->db->get('mytable');
make sure FALSE is without single quotes (makes it a string), and it might not validate (not tested by me).
I think you should check DB_driver.php file, there is a variable named as protect_identifier, the point is when you will check with older version of CI, you will see that there is a condition which is missing in new version,escape variable which is checked for nullability, paste that condition from older version and you will be OK
CI_DB_active_record::where() has a third param for escaping, this has worked better for me than switching on and off CI_DB_driver::_protect_identifiers
public function where($key, $value = NULL, $escape = TRUE)
Not sure what CI version this was added in.
HTH someone
Here's a trick that worked for me. Replace this line
$this->db->join($this->_table_device, $fieldname1. " = ". $fieldname2, 'LEFT');
with this:
$this->db->join($this->_table_device, $fieldname1. " IN(". $fieldname2 .")", 'LEFT');
this will prevent CI from escaping your field. It's not ideal but it's better than the alternatives.
I just read a simple solution for this...
I changed the value of var $_escape_char (system/database/drivers/mysql/mysql_driver.php, line 36..
It was
var $_escape_char = '`';
Changed to
var $_escape_char = ' ';
and now it works... But i am affraid if I made any security issues..
Thanks