I am trying to get data from a database that meets multiple criteria of an array.
The array is something like this:
Array ([21] => 1,[23] => 0,[19] => 1);
With the key being a Question ID and the values being either yes or no.
I need to find the movie where the value for question_id = 21 is 1, value for question_id = 23 is 0 and value for question_id = 19 is 1. The way I have them stored is like this:
So my first thought was get the data for each and then put them in a bigger array. If the movie shows up the same amount of times as the number of elements in the array, then I consider it a good match. But this seems inefficient. I would rather just find the movies that match the criteria.
Since there are movie_id records with the same value, is there a way to write something like this?:
foreach($array as $key=>$value){
$i++;
$this->db->where('question_id', $key);
$this->db->where('value', $value);
}
$this->db->from('movies_values');
$query = $this->db->get();
$res = $query->result();
array_push($main,$res);
The thought behind this is to create a loop of all the WHEREs. And then run the query using those where values. This doesn't seem to work, is there something else I can do?
How about using WHERE IN (array())?
From the CI User Guide:
$names = array('Frank', 'Todd', 'James');
$this->db->where_in('username', $names);
// Produces: WHERE username IN ('Frank', 'Todd', 'James')
Use the where_in method for lists:
$this->db->where_in('value', $array);
Try doing it like this.
$where = WHERE 1
foreach($array as $key=>$value){
$where .= " AND(question_id = $key AND value = $value)";
}
$this->db->where($where);
PS. What is the $i++ doing in your loop exactly?
I think this is the right way to go, you should take care to use "or" instead to use full "ands" that way would not return any row due to a logic problem (I mean question_id = 1 and value = 1 and question_id = 2 and value = 0 we're being inconsistent due to telling that we want question_id = 1 and question_id = 2 won't match nothing!, the same applies to "values").
$array = array(21 => 1,23 => 0,19 => 1);
$where = array();
foreach($array as $key => $value) {
$where[] = "(question_id=$key and value=$value)";
}
var_dump($where);
foreach ($where as $value) {
$this->db->or_where($value);
}
$q = $this->db->get('movies_values')->result();
var_dump($q);
echo $this->db->last_query();exit;
This can be done easily without loop:
$filter = array(21 => 1,23 => 0,19 => 1);
$values = implode(',',array_unique(array_values($filter))); // results into 0,1...
$keys = implode(',',array_unique(array_keys($filter))); // results into 19,21,23...
$result = $this->db
->query("select * from movies_values
where
question_id in(".$keys.")
and value in(".$values.")")
->result();
Happy coding ---> :)
Related
In a table unit, I have 18 columns which can contain one of three different values in each of the columns. The possible values are 'N', 'I' or 'ETP'.
Three of those columns are:
|------------|-------------|------------|
|gcc_1_1 |gcc_1_2 |gcc_1_3 |
|------------|-------------|------------|
I want to return counts of each of those three values for each column to put into their own variables, e.g. the following variables would be for the first column and the three possible values.
$gcc_1_1_n
$gcc_1_1_i
$gcc_1_1_etp
What would be the simplest way of achieving this in PHP using one MySQL query?
$query = "SELECT * FROM unit";
$result = $connection->query( $query );
while ($row = mysqli_fetch_array($result)) {
...
}
you could do something like this
<?php
$data = [...]; //array of data in the form of [['gcc_1_1' => 'n',... ], ...]
$groupedData = array_reduce(
$data,
function(array $res, array $row){
foreach($row as $column => $value) {
$key = $column.'_'.$value;
$existing = $res[$key] || 0;
$res[$key] = $existing + 1;
}
return $res;
},
[]
);
Now in your $groupedData you have an array with keys that matches your request.
You can use extract() to create n variables but I think you shouldn't do it because it's harder to handle and debug for future issues
I want to do something like this
----sql output----
name TEXT
b
c
$arr = ["a","b","c","d"];
foreach($arr as $key=>$val){
$query = "select count(*) from mydata where name = $val";
$count = xxxx($query);
if($count)unset($arr[$key]);
}
And $arr will be
a,d
Any simple way to do it but not checking every single element?
---edited---
I think I solve my problem myself...getting some inspired from mrlore that using having.
$arr = ["a","b","c","d"]; /* make the string inside arr safe for query */
$val = array_map(function($val){return "'$val'";},$arr);
$q = "select name from mydata where name in (" . implode(',',$val) .")";
$all = xxxxx($q);
$arr = array_diff($arr,$all);
This took me 0.8 second. Using my old way take 46 second and RST way takes 2 seconds.
---edited----
I have over 200k rows of data in my database, so I want a better way to optimize it.
--re MrLore--
ps : I don't know how to use stackoverflow to posting comments..so I just edit my post.
I have tried it on my mysql workbench but it does not seem to work for me.
select name from mydata
where name in("a","b","c","d")
having count(name) = 0
-- returns nothing
select name from mydata
where name in("a","b","c","d")
having count(name) > 0
$arr = ["a","b","c","d"];
$query = "select DISTINCT name from mydata";
$results = <result of query>;
foreach ($results as $result){
if(($key = array_search($result, $arr)) !== false) {
unset($arr[$key]);
}
}
Or the other way around
foreach ($arr as $key=>$value){
if( in_array( $value, $results) ) {
unset($arr[$key]);
}
}
By querying DISTINCT the database only returns unique values. You can then compare them with the array you have and remove them.
in my laravel project i have a db field in which user can store the parameters that to be considered for sorting and also their orders. That is, the data table "config" contains a column value like this
status-desc,priority-asc,..etc
In here, when i write the query i need to use these values as the order by pairs.
ORDER BY status desc, priority asc
I can hard code this in the query code like the above because the sorting columns can be different based on the users entry.
i already exploded two criteria separately like this
$params = explode(',', $sort_param->config_value);
so that i got $params[0] = status-desc and $params[1] = priority-asc ...
But how can i again explode these and fetch and use them in the query for order by??
what i did so far is:
$countt = count($params);
for($prm=0;$prm<$countt;$prm++){
list($k, $v) = explode('-', $params[$prm]);
}
echo $k.' '.$v;
The echo $k and $v displays priority asc
Try
$tab = 'status-desc,priority-asc,value,string,demo';
$params = explode(',',$tab);
foreach($params as $v){
$tab2[] = explode('-',$v);
}
$newTab = array_merge($params,$tab2);
print_r($newTab);
Try with this simple code
$tab = 'status-desc,priority-asc,value,string,demo';
list($statut,$priority,$value,$demo) = explode(',',$tab);
echo $statut ;
I have the following codes:
$spaces=0;
$str="bike car ";
for($i = 0; $i < strlen($str); $i++)
{
if($str[$i]==" ")
{
$spaces+=1;
}
}
$names=explode(" ",$str);
The above code is used to split the words inside the string. How do i do a db query wherein i get the id of the names(words in the string i separated).
Assuming, i have a price table
The table has lets say 2 cols, item name and id
How do i parse DB query wherein i need to get the ids of the item names listed.
I guess you want to get the id of exploded $name simply you can use $this->db->where_in()
example :
$names = array('Frank', 'Todd', 'James');
$this->db->where_in('username', $names);
// Produces: WHERE username IN ('Frank', 'Todd', 'James')
See the documenation here : Where In Query
So the next line of your code maybe seems like this one :
$names = explode(" ",$str);
$this->db->select('id')
->where_in('your_table_name',$names);
$query = $this->db->get();
$result = $query->result_array();
then you can use the $result by
foreach($result as $r){
echo 'The id is :'.$r['id'];
}
You can simple use array_keys and array_values to traverse you array keys and values
//sample array
Array
(
[1334] => Face Towel
[4552] => White Socks
[3442] => Lotion
[6643] => Pants
[4432] => foobar
[5532] => bar
)
$items = implode(',',array_values($array)); //will get the array values
$itemid = implode(',',array_map('intval',array_keys($array))); //will get the array keys
$this->db->where_in('items', $items);
// where items IN ('Face Towel','White Socks','Lotion','pants','foobar','bar')
$this->db->where_in('itemid', $itemid);
// where itemid IN (1334,4552,3442,6643,4432,5532)
Note that i used array_map to loop through each keys and cast every key as integer.
I need to sort an associative-array in the exact order of the content of another array.
The Arrays are retrieve by 2 separate sql-requests (stated below). The requests could not be combined to only one request, so I have to sort the second array into the order of the first one.
These are the arrays:
#Array which contains the id's in needed order
$sorting_array = array(1,2,3,8,5,6,7,9,11,10...);
#Array which contains the values for the id's, but in order of "id" ASC
$array_to_sort = array(
array("id" => "1", "name" => "text1", "help" => "helptxt2");
array("id" => "2", "name" => "text2", "help" => "helptxt2");
);
The SQL-Queries:
SQL-Ouery for $sorting_array: (the db-field 'conf' is setup as "text", maybe this is my problem so that I have to first explode and implode the entries before I could use it for the next query.)
$result = sql_query("select conf from config where user='me'", $dbi);
$conf = sql_fetch_array($result, $dbi);
$temp = explode(',', $conf[0]);
$new = array($temp[0], $temp[1], $temp[2], $temp[3],$temp[4],
$temp[5], $temp[6], $temp[7], $temp[8], $temp[9],
$temp[10], ...);#Array has max 30 entries, so I count them down here
$sorting_array = implode(',', $new);
SQL-Ouery for $array_to_sort:
$result = sql_query("SELECT id, name, helptxt
FROM table
WHERE id IN ($sorting_array)
AND language='english'");
while ($array_to_sort[] = mysql_fetch_array ($result, MYSQL_ASSOC)) {}
array_pop($array_to_sort);#deleting the last null entry
I could access $array_to_sort as follows to see the content one by one:
(if the lines below don't match the array above, than I mixed it up. However, the lines below is what brings the content)
echo $array_to_sort[0]["id"];
echo $array_to_sort[0]["name"];
echo $array_to_sort[0]["helptxt"];
But it is sorted by "id" ASC, but I need exactly the sorting as in $sorting_array.
I tried some things with:
while(list(,$array_to_sort) = each($sorting_array)){
$i++;
echo $array_to_sort . "<br>";
}
which only brings the Id's in the correct order, but not the content. Now I'm a bit confused, as I tried so many things, but all ended up in giving me the same results.
Maybe the sql-query could be done in one step, but I didn't brought it to work.
All results to my searches just showed how to sort ASC or DESC, but not what I want.
Furthermore I must confess that I'm relative new to PHP and MySQL.
Hopefully some one of you all could bring me back on track.
Many thanks in advance.
To fetch your results:
$result = mysql_query("SELECT id, name, helptxt
FROM table
WHERE id IN ($sorting_array)
AND language='english'");
$array_to_sort = array();
while ( ($row = mysql_fetch_assoc($result)) !== false ) {
// associate the row array with its id
$array_to_sort[ $row[ "id" ] ] = $row;
}
To display them in order of $sorting_array:
foreach ( $sorting_array as $id ) {
// replace the print_r with your display code here
print_r( $array_to_sort[ $id ] );
}
And a bonus tip for the code fetching $sorting_array:
$result = mysql_query("select conf from config where user='me'", $dbi);
$conf = mysql_fetch_array($result, $dbi);
$temp = explode(',', $conf[0]);
// limit to 30 ids
$new = array();
// no need to do this manually, use a loop
for ( $i = 0; $i < 30; ++$i )
$new[] = $temp[ 0 ];
$sorting_array = implode(',', $new);
Its a little hard to tell because there is a lot going on here, in the future you'll probably get better/more responses if you ask several simple questions and figure out yourself how to make the answers fit together.
Your best bet long term is going to be to restructure your SQL tablessuch that you can combine these query together. You can do what you're asking in PHP, but it's going to be slower than doing it in MySQL and much more complicated.
To do what you're asking (pretty slow in PHP):
$sorted = array();
foreach ( $sorting_array as $id )
{
foreach ( $array_to_sort as $values )
{
if ( $values['id'] == $id )
{
$sorted[] = $values;
break;
}
}
}
what I tend to do in such a situation is first to rearrange the array with the data. so the keys represent ids
In your case:
$array_to_sort_ids = array();
foreach ($array_to_sor as $item)
{
$array_to_sort_ids[$item['id']] = $item;
}
Then sorting is as simple as:
$array_sorted = array();
foreach ($sorting_array as $id)
{
$array_sorted[] = $array_to_sort_ids[$id];
}
This solution is quite efficient, since you only have 2 foreach loops.
EDIT!!!
As I couldn't edit my question anymore, I just like to state my solution this way:
The tip to rethink my database was what brought me to some testings and then I found the solution, with the following query:
$result = sql_query("SELECT id, name, helptxt
FROM table
WHERE id IN ($sorting_array)
AND language='english'
ORDER BY FIELD(id,$sorting_array)");
while ($array_to_sort[] = mysql_fetch_array ($result, MYSQL_ASSOC)) {}
array_pop($array_to_sort);#deleting the last null entry
Just the line:
ORDER BY FIELD(id,$sorting_array)
will do the trick. It orders the results the way you want, even if this means 1,4,2,3,9,7,...
Sometimes it's so easy, when you know where to look.
Thanks again!!!