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]);
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 am using buddypress on a wordpress installation. I would like to get an array of user_ids into a variable which I can then use to manipulate, for example, list in HTML or send messages to.
I have tried using the following code. I have verified my SQL query is correct via phpmyadmin.
function my_bp_get_users_by_xprofile( $field_id, $value ) {
global $wpdb;
$user_ids = $wpdb->get_col(
$wpdb->prepare(
"
SELECT `user_id`
FROM '{$wpdb->prefix}bp_xprofile_data'
WHERE `field_id` = %d
AND `value` = %s
"
, $field_id
, $value
)
);
}
Then on the page, I want to do something like this:
$user_ids = my_bp_get_users_by_xprofile( 5, '%18%' );
echo $user_ids;
I have also verified the location of my php (bp-custom) by invoking a simple function that simply echos a string.
Where am I going wrong?
I think you're missing a return in your function, so you're calling the method but not returning anything.
function my_bp_get_users_by_xprofile( $field_id, $value ) {
global $wpdb;
$user_ids = $wpdb->get_col(
$wpdb->prepare(
"
SELECT `user_id`
FROM '{$wpdb->prefix}bp_xprofile_data'
WHERE `field_id` = %d
AND `value` = %s
"
, $field_id
, $value
)
);
// Return only if there are user_id's found
if (!empty($user_ids) {
return $user_ids;
}
// Return false if nothing found
return false;
}
Then in your template you'd need to also check if its not empty:
$user_ids = my_bp_get_users_by_xprofile( 5, '%18%' );
if ($user_ids) {
// You first need to see what the structure of the returned array is and what values the indexes have
echo $user_ids['value'];
}
I have two models set up for an array. Basically, what I want to achieve is to get the first next entry from the database based on the order ID I have set up.
So, I send the ID 4, I find the entry with the ID 4 which has the order ID 15. Then I want to get the first next item after it, which should have the order ID 16. I tried incrementing with +1 after the order ID, but it just doesn't work.
With my current code I get the same array twice.
function first($id_domain) {
$this->db->select ( '*' );
$this->db->from ( 'domains' );
$this->db->where ( 'id_domain', $id_domain);
$result = $this->db->get ();
return $result->result_array ();
}
function second ($result) {
$this->db->select ( '*' );
$this->db->from ( 'domains' );
$this->db->where ( 'order', $result[0]['order'] + 1 ); //code that should get me the next entry, but doesn't work...
$this->db->where ( 'parent', $result[0]['parent'] );
$result2 = $this->db->get ();
return $result2->result_array ();
}
The problem is not due to your code, but it may be due to the records in the database: either they are non-existing for that specific condition or your matching is not entirely correct.
If you are using CodeIgniter I suggest you to alter your second function to this:
function second($result) {
$whereConds = array(
'order' => intval($result[0]['order'] + 1),
'parent'=> $result[0]['parent']
);
//if you don't have firephp print/echo/var_dump as you normally would
$this->firephp->log($whereConds);
$query = $this->db->get_where('domains', $whereConds);
$this->firephp->log($this->db->last_query());
if ($query->num_rows() <= 0) {
$this->firephp->log('No results');
return array();
} else {
return $query->result_array();
}
}
This way you can track the problem accurately.
Btw, you can also use the $offset parameter in the get_where to get the next id (perhaps just with the parent condition, since you know they are ordered sequentially):
$limit=1;
$offset=intval($result[0]['order'] + 1);//adjust depending on the parent condition below: it can be just an integer such as 2
$whereConds = array(
'parent'=> $result[0]['parent']
);
$query = $this->db->get_where('domains', $whereConds, $limit, $offset);
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.
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 :)