Nested where clauses codeigniter mysql query - codeigniter

Is there any way to get nested where clauses? e.g.:
SELECT * FROM table WHERE (colA = 'valueA' AND colB = 'valueB') OR (colA = 'valueC' AND colB = 'valueD')
I know I could just write this into a query function call e.g.:
$this->db->query("SELECT ...")
But I was wondering if there was a "proper" way to do it in codeigniter e.g.:
$this->db->where(array('colA'=>'valueA'), array('colB'=>valueB'))->or_where(array('colA'=>'valueC'), array('colB'=>'valueD'))
thanks

With codeigniter 3, now there is, see the update!
There's no where() method usage variant with arrays that would allow you to do that. In these situations i usually just build the part in one long string like this:
$this->db->where("
(
(colA = '".$this->db->escape($v0)."' and colB = '".$this->db->escape($v1)."')
or
(colA = '".$this->db->escape($v2)."' and colB = '".$this->db->escape($v3)."')
)
");
Escaping can be done with escape(does some autodetection) or escape_str or escape_like_str manually depending on what the parameter expected to be or what the predicate in use.
If i'm on a project that uses the Datamapper library, i prefer to use the group_start() and group_end() methods when building these kind of queries, they have a lot of different flavor of these.
Update
Now with, Codeigniter 3 which have grouping methods in the query builder, so you can do ->group_start()s and ->group_end()s.

You can also try like
$this->db->where(condition1);
$this->db->or_where(condition2);

Related

Project a single column of a table filtered by tag from act as taggale

Currently the only way I know to sub select in rails is with arel,
for exmaple -
sub = x.where(y:'x').project(:id)
select = a.where(a[:x_id].in(sub))
question is,
if x is using the acts as taggable on gem and need to filtered by a specific tag, use with tagged_with method.
How can I still achive same database efficiency, it looks like the tagged with method override the projection.
thanks,
You don't need Arel to build sub selects in Rails:
sub = X.where(y: 'x')
select = A.where(x_id: sub)
generates the following SQL, assuming A's table name is as and X's is xs:
SELECT "as".* FROM "as" WHERE "as"."x_id" IN (SELECT "xs"."id" FROM "xs" WHERE "xs"."y" = 'x')
Testing with tagged_with worked: A.where(x_id: X.tagged_with('my_tag')) generates the expected SQL, at least for Rails 5.1, version on which I've tested.
Edit
You can specify the column used inside the subselect if needed. If you don't specify it, the primary key column is the default:
sub = X.where(y: 'x').select(:x_y_id)
select = A.where(x_id: sub)
will generate the following SQL:
SELECT "as".* FROM "as" WHERE "as"."x_id" IN (SELECT "xs"."x_y_id" FROM "xs" WHERE "xs"."y" = 'x')

Laravel get all the values of a column beginning with a number

I have a model called "Image" and a table called "images". The table has a column for the "id" and another for the "name". I need to fetch only the rows with the name beginning with a number.
I need to fetch are called something like
16783521_facebook.png
While the others are something like...
twiter.png
Try this:
Image::whereRaw("name REGEXP '^[0-9]'") -> get();
If it's something you're going to use in more than 1 place, consider moving it to a scope.
In your image model define something like:
public function scopeNumeric($query)
{
return $query -> whereRaw("name REGEXP '^[0-9]'");
}
Then you can just use:
Image::numeric() -> get();
I dont know much about laravel, but this plain query will help -
SELECT * FROM mytable WHERE mycolumn REGEXP '^[0-9]+$' or
SELECT * FROM myTable WHERE col1 REGEXP '[0-9]+';
Laravel doesn't have that built-in, so you'll have to make do with raw queries. In its base form:
$results = SomeModel::whereRaw("some_column REGEXP '^[0-9]'")->get();
You can modify this as usual with selects, other limitations, etc. as you require.
Filter the images after the query using one of the collection methods. Like below solved me.
$onlyNumeric = $photos->filter(function ($value, $key) {
return is_numeric(substr($value, 0, 1));
});

ActiveRecord 4 cannot retrieve "select AS" field

Ok, I feel really stupid for asking this, but it's driving me nuts and I can't figure it out. The docs say I should be able to use select AS in a Rails/ActiveRecord query. So:
d = Dvd.where(id: 1).select("title AS my_title")
Is a valid query and if I do a to_sql on it, it produces the expected SQL:
SELECT title AS my_title FROM `dvd` WHERE `dvd`.`id` = 1
However, d.my_title will give an error:
NoMethodError: undefined method `my_title' for #<ActiveRecord::Relation
I need to be able to use AS since the columns I want to retrieve from different joins have the same name so I can't access them the "regular" way and have to resort to using AS.
I also don't want to resort to using find_by_sql for future compatibility and a possible switch form Mysql to PostGresql.
Just to clarify, what I'm really trying to do is write this SQL in a Railsy way:
SELECT tracks.name AS track_name, artists.name AS artist_name, composers.name AS composer_name, duration
FROM `tracks_cds`
INNER JOIN `tracks` ON `tracks`.`id` = `tracks_cds`.`track_id`
INNER JOIN `artists` ON `artists`.`id` = `tracks_cds`.`artist_id`
INNER JOIN `composers` ON `composers`.`id` = `tracks_cds`.`composer_id`
WHERE cd_id = cd.id
The top example was just a simplification of the fact that SELECT AS will not give you an easy way to refer to custom fields which I find hard to believe.
ActiveRecord automatically creates getter and setter methods for attributes based on the column names in the database, so there will be none defined for my_title.
Regarding the same common names, why not just do this:
d = Dvd.where(id: 1).select("dvds.title")
You can write your sql query and then just pass into ActiveRecord's execute method
query = "SELECT title AS my_title FROM `dvd` WHERE `dvd`.`id` = 1"
result = ActiveRecord::Base.connection.execute(query)

How to use 'IN (1,2,3)' with findAll?

I need to get a couple of Students from the database, and I have their primary keys in a comma-separated string.
Normally using SQL it would be something like:
$cleanedStudentIdStringList = "1,2,3,4";
SELECT * FROM Student WHERE id IN ($cleanedStudentIdStringList)
Yii's ActiveRecord seems to insert a single quote around bound parameters in the resulting SQL statement which cause the query to fail when using parameter binding.
This works, but doesn't use safe parameter binding.
$students = Student::model()->findAll("id IN ({$_POST['studentIds']})");
Is there a way to still use parameter binding and get only a couple of rows in a single query?
You can do it also that way:
$criteria = new CDbCriteria();
$criteria->addInCondition("id", array(1,2,3,4));
$result = Student::model()->findAll($criteria);
and use in array any values you need.
Aleksy
You can use findAllByAttributes method also:
$a=array(1,2,3,4);
$model = Student::model()->findAllByAttributes(array("id"=>$a));

Is this linq query efficient?

Is this linq query efficient?
var qry = ((from member in this.ObjectContext.TreeMembers.Where(m => m.UserId == userId && m.Birthdate == null)
select member.TreeMemberId).Except(from item in this.ObjectContext.FamilyEvents select item.TreeMemberId));
var mainQry = from mainMember in this.ObjectContext.TreeMembers
where qry.Contains(mainMember.TreeMemberId)
select mainMember;
Will this be translated into multiple sql calls or just one? Can it be optimised? Basically I have 2 tables, I want to select those records from table1 where datetime is null and that record should not exist in table2.
The easiest way to find out if the query will make multiple calls is to set the .Log property of the data context. I typically set it to write to a DebugOutputWriter. A good example for this kind of class can be found here.
For a general way of thinking about it however, if you use a property of your class that does not directly map to a database field in a where clause or a join clause, it will typically make multiple calls. From what you have provided, it looks like this is not the case for your scenario, but I can't absolutely certain and suggest using the method listed above.

Resources