I'm having some issues getting codeigniter active record to produce a query like this:
SELECT fruits.* FROM fruits
WHERE fruits.color = 'red'
AND ( fruits.size = 'medium' OR fruits.name = 'kiwi' OR fruits.length = 7 );
Basically I want to have several or clauses but one where clause that is always enforced.
$this->db->select( 'fruits.*' );
$this->db->from( 'fruits' );
$this->db->where( 'fruits.color', 'red' );
$this->db->or_where( 'fruits.size', 'medium' );
$this->db->or_where( 'fruits.name', 'kiwi' );
$this->db->or_where( 'fruits.length', 7 );
Produces something like:
SELECT fruits.* FROM fruits WHERE fruits.color = 'red' OR fruits.size = 'medium' OR fruits.name = 'kiwi' OR fruits.length = 7;
I need to enforce that color is always red.
Is there a decent way to do this?
There is no way to achieve this properly using CodeIgniter Active Record.
The only way that's not too ugly is using a custom string with the where() function like this:
$this->db->select( 'fruits.*' );
$this->db->from( 'fruits' );
$where = "fruits.color = 'red' AND ( fruits.size = 'medium' OR fruits.name = 'kiwi' OR fruits.length = 7 );";
$this->db->where( $where );
IMPORTANT: note that using a custom string, your variable WILL NOT be escaped, thus, you need to use $this->db->escape()
$this->db->select( 'fruits.*' );
$this->db->from( 'fruits' );
$color = 'red';
$size = 'medium';
$name = 'kiwi';
$length = 7;
$where = "fruits.color = '".$this->db->escape($color)."' AND ( fruits.size = '".$this->db->escape($size)."' OR fruits.name = '".$this->db->escape($name)."' OR fruits.length = '".$this->db->escape($length)."');";
$this->db->where( $where );
Edit:
I got confused on the good query, I corrected it :)
Related
I want to call the method $wpdb->get_results(),
and I need to add parameters (WHERE clauses) to the SQL query.
The thing is, I want to build a generic function that will receive a parameters object and will generate an SQL query which includes my parameters.
So, for example, if this is my base query:
$taxis = $wpdb->get_results("SELECT * FROM $table", ARRAY_A); // base query
And these are my parameters:
$params = array(
'color' => 'blue',
'model' => 'ford'
);
It will call get_results with the following query:
SELECT * FROM $table WHERE color='blue' AND model='ford';
Is there a way to build a function that will have this behaviour?
*NOTES:
I don't know how many parameters are going to be in the parameters object nor which parameters they will be (that is why it has to be generic).
I do know, (in my case) that the only SQL CLAUSES I am going to need are WHERE =.
See the code comments for an explanation on what is happening in each step:
<?php
// make sure this doesn't come from user input, as it is inserted into the query directly
$tableName = $wpdb->prefix . "yourtable";
$columnWhitelist = array( 'color', 'model' );
$params = array(
'color' => 'blue',
'model' => 'ford'
);
// filter param keys by allowed column names defined in $columnWhitelist
$params = array_filter(
$params,
function ( $key ) use ( $columnWhitelist ) {
return in_array( $key, $columnWhitelist );
},
ARRAY_FILTER_USE_KEY
);
$whereClauseParts = array();
// put column/value pairs of $params into $placeholderValues array
$placeholderValues = array();
foreach ( $params as $column => $value) {
$whereClauseParts[] = "`$column` = %s";
$placeholderValues[] = $value;
}
// put together the WHERE clause with placeholders
$whereClause = implode(' AND ', $whereClauseParts );
// put together the whole query tring
$queryString = "SELECT * FROM `$tableName` WHERE " . $whereClause;
// you can use this to see what your prepared query will roughly look like,
// but with missing single quotes around the values
// die( vsprintf(
// $queryString,
// $placeholderValues
// ) );
$wpdb->get_results(
$wpdb->prepare(
$queryString,
$placeholderValues
)
);
I'm looping through contacts, pulling out specific data then want to update a particular column on the current row. How can I do that?
The line is at the very bottom, I just want to change it from a 0 to 1.
require('../mailin.php');
$mailin = new Mailin("https://api.sendinblue.com/v2.0","Your access key");
$customer_data = $wpdb->get_results("SELECT * FROM imp_customer_log WHERE updated_in_sib = '0'");
foreach( $customer_data as $customer ) {
$customer_id = $customer[0];
$customer_event = $customer[1];
$customer_data = $customer[2];
$customer_sib = $customer[3];
$user = get_user_by( 'id', $customer_id );
$user_email = $user->user_email;
$data = array(
"email" => $user_email,
"attributes" => array(
$customer_event => $customer_data,
),
);
var_dump($mailin->create_update_user($data));
// Change updated_in_sib to 1 for current row
}
i assume that this is a wordpress. you can use the update function in wpdb something look like this.
$wpdb->update('imp_customer_log', ['customer_sib' => 1], ['id' => $customer_id]);
you can check the it on documentation. https://codex.wordpress.org/Class_Reference/wpdb#UPDATE_rows
for php (not wordpress)
$sql = "UPDATE imp_customer_log SET customer_sib=1 WHERE id=" . $customer_id;
$connection->query($sql);
I think you're using Wordpress. Take a look at these wordpress docs for update, used just like get_results() in your question.
https://developer.wordpress.org/reference/classes/wpdb/update/
$wpdb->update( string $table, array $data, array $where, array|string $format = null, array|string $where_format = null )
I got a database running on mysql 5.7.11 and has a lot of data into a table with JSON column. I got a raw query like this one.
select * from `note`
where `note_structure_id` = 3
and JSON_EXTRACT(LCASE(data), '$._letter') = 'a'
and JSON_EXTRACT(data, '$._number') = 1
Running in sequel pro or phpmyadmin it gives me a result what i expect;
{"_letter": "A", "_number": 1}
The same query i build with laravel it gives me a result of nothing. An empty array. My code to building the same query i got this kind of code.
$result = \DB::table( 'note' )->where( 'note_structure_id', $structureId );
if( is_array( $query ) ) {
if( isset( $query['where'] ) ) {
foreach( $query['where'] AS $field => $value ) {
if( is_numeric( $value ) ) {
$result = $result->where( \DB::raw( "JSON_EXTRACT(data, '$._{$field}')" ), '=', $value );
}
else {
$result = $result->where( \DB::raw( "JSON_EXTRACT(LCASE(data), '$._{$field}')" ), '=', strtolower( $value ) );
}
}
}
}
dd($result->get());
Did anyone knows what i did wrong with my code or something. I try everything what's possible for fixing it but without result.
Thanks!
Saw you fixed it, but why not just do as a raw query, in a more traditional way. Your code is not very readable at the moment.
$results = DB::select('select * from `note` where `note_structure_id` = :id and JSON_EXTRACT(LCASE(data), `$._letter`) = :a and JSON_EXTRACT(data, `$._number`) = :number', ['id' => 3, 'a' => 'a', 'number' => 1]);
I am coding a search module. I do not know if I am ina good way but ti sound good for now excepted one point.
With the following code I can search only one word.
<?php
class SearchesController extends AppController{
function index(){
if($this->request->is('put') || $this->request->is('post') ){
// Save the send data
$search = $this->request->data['Search']['key'];
//$nbWords = str_word_count($search);
/*
THIS DOES NOT WORKS
if($nbWords > 1){
$searchTerms = explode(' ', $search);
$searchTermBits = array();
foreach ($searchTerms as $term) {
$term = trim($term);
if (!empty($term)) {
$searchTermBits[] = "Page.name LIKE '%$term%' AND Page.content LIKE '%$term%'";
}
}
}else{
$term = $search;
$searchTermBits[] = "Page.name LIKE '%$term%' AND Page.content LIKE '%$term%'";
}
*/
// SEARCH IN Pages TABLE
$this->loadModel('Page');
// SAVE THE RESULT IN
$d['pages'] = $this->Page->find('all', array(
'conditions' => array(
'online'=>'1',
'type'=>'page',
'created <= NOW()',
'id > 1',
'OR' => array(
//implode(' AND ', $searchTermBits)
'Page.name LIKE'=>'%'.$search.'%',
'Page.content LIKE'=>'%'.$search.'%'
)
),
'fields' => array('name','content','created','id','type')
));
//SEARCH IN Posts TABLE
$this->loadModel('Post');
$d['posts'] = $this->Post->find('all', array(
'conditions' => array(
'online'=>'1',
'type'=>'post',
'created <= NOW()',
'OR' => array(
'Post.name LIKE'=>'%'.$search.'%',
'Post.content LIKE'=>'%'.$search.'%'
)
),
'fields'=> array('name','content','created','id','type','slug')
));
// SEND THE VALUES TO THE VIEW
$this->set($d);
}else{
echo 'e';
}
}
}
The problem, I would like to be able to search with different words, for exeple "red car", "house monrain","web html5 development"
With my code, if I enter one word, it return a result, but if I add second word to the first (with a space) , it retuirn no result.
How can I change this
'OR' => array(
'Post.name LIKE'=>'%'.$search.'%',
'Post.content LIKE'=>'%'.$search.'%'
)
to make it able to search in 'name' and 'content' several words?
Thak for your help
Cheers
you can try this:
'OR' => array(
'Post.name' IN ('name1', 'name2'),
'Post.content' IN ('content1', 'content2')
)
Obviously you can put your value in array like this:
$name_arr = array();
$name_arr[] = 'name1';
$name_arr[] = 'name2';
and after:
'OR' => array(
'Post.name' IN ($name_arr),
'Post.content' IN ('content1', 'content2')
)
Change your $search variable
$search = $this->request->data['Search']['key'];
// if keywords "red car" then it will pass to your query %red%car%;
$search = str_replace(" ","%",$search);
Now it will search records having both words.
If you want to search with many words separated by a space, you can do this.
$searches = explode(" ", $search);
foreach ($searches as $search) {
//put your search condition in here
}
You might look into fulltext searching. If you setup your indices correctly, you can run queries such as:
SELECT id, MATCH (title,body) AGAINST ('Tutorial') FROM articles;
Hi Codeigniter Experts.
I'm compiling a QUERY by several calls to a function.
When it is done I'll use the QUERY to retrieve some data of course.
Each call, calls another function which gets and returns some translations which is supposed to be used in the QUERY
But it seems like that the WHERE condition in translation funciton gets concatinated by the WHERE condition which I'm compiling in the main QUERY
private function add_to_asq($field_name, $values)
{
.
.
.
.
$result = array();
foreach( $values[$last_level] as $val )
{
foreach( $val as $v )
{
$result[] = $this->db->escape( $this->asq_value_translate( $last_level, $v, $field_name ) );
}
}
$this->db->where_in( sprintf( '%1$s' , $field_name ) , implode( ',' , $result ) );
}
private function asq_value_translate( $level, $value_md5 , $field_name )
{
$this->db->select( sprintf( 'level_%1$d, level_%1$d_value' , $level ) )
->distinct()
->from('search_options_tree_view')
->where( sprintf( 'md5( level_%1$d_value ) = ' , $level ), $value_md5 )
->where( 'field_name' , $field_name );
$q = $this->db->get();
$value_name = sprintf( 'level_%1$d' , $level );
$row = $q->row(0);
$q->free_result();
return $row->$value_name;
}
and the DB complains about it
Error Number: 1054
Unknown column 'type' in 'where clause'
SELECT DISTINCT `level_1`, `level_1_value` FROM (`search_options_tree_view`) WHERE
`type` IN ('\'Forhandler\'')
AND md5( level_1_value ) = '138be735c55896dbdbea9b6c5d503b6f' AND `field_name` = 'fuel'
Filename: C:\wamp\www\system\database\DB_driver.php
Line Number: 330
As you see the type IN ('\'Forhandler\'') has not anything to with the asq_value_translation.
Do you have a suggestion?
I've thought of cloning the db-object but then I thought that I ask first and shoot later.
Thanks a lot and have a nice time.
You should use $this->db->last_query() to see what the output of your query actually is. Then take that query and run it in your db client to make sure the issue is not in codeigniter, but rather in your query.