MySQL (exploding/matching array) - php

Question1:
MySQL table
id | array
1 | 1,2,3
2 | 2
3 | 2,3
4 | 4,5,6
$_GET['id'] = 2;
$a = mysql_query("SELECT * FROM `table` WHERE `array` ??? '$_GET[id]'");
In this step, I want to run through the entire array and see if it matches with the $_GET['id'], so it should output:
ids: 1,2,3
Question2:
MySQL table
id | array
1 | 4,5,6
2 | 3,4,7
$_GET['id'] = 4;
$a = mysql_query("SELECT * FROM `table` WHERE `array` ??? '$_GET[id]'");
In this step, I only want to match against the first element in the array, so it should output:
id: 4
I can only think of using PHP to do this, but I'd rather do all that just within the MySQL query, if that is even possible.
$a = mysql_query("SELECT * FROM `table`");
while($b = mysql_fetch_assoc($a))
{
$elements = explode(',', $b['array']);
foreach($elements as $element)
{
if($element == $_GET['id'])
{
echo $b['id'].'<br />';
}
}
}
or
$a = mysql_query("SELECT * FROM `table`");
while($b = mysql_fetch_assoc($a))
{
$array = $b['array'];
if(in_array($_GET['id'], $array))
{
echo $b['id'].'<br />';
}
}
that would look just awful.

That you can/should structure your database differently has already been mentioned (see http://en.wikipedia.org/wiki/Database_normalization). But....
See FIND_IN_SET()
mysql> SELECT FIND_IN_SET('b','a,b,c,d');
-> 2
e.g.
<?php
$mysql = init();
bar($mysql, 1);
bar($mysql, 2);
bar($mysql, 3);
bar($mysql, 4);
function bar($mysql, $x) {
$sql_x = mysql_real_escape_string($x, $mysql);
$result = mysql_query("SELECT id, foo FROM soTest WHERE FIND_IN_SET('$sql_x', foo)", $mysql) or die(mysql_error());
echo "$x:\n";
while( false!==($row=mysql_fetch_array($result, MYSQL_ASSOC)) ) {
echo $row['id'], ' ', $row['foo'], "\n";
}
echo "----\n";
}
function init() {
$mysql = mysql_connect('localhost', 'localonly', 'localonly') or die(mysql_error());
mysql_select_db('test', $mysql) or die(mysql_error());
mysql_query('CREATE TEMPORARY TABLE soTest (id int auto_increment, foo varchar(64), primary key(id))', $mysql) or die(__LINE__.' '.mysql_error());
mysql_query("INSERT INTO soTest (foo) VALUES ('1,2,3'), ('2,4'), ('3'), ('2,3'), ('1,2')", $mysql) or die(__LINE__.' '.mysql_error());
return $mysql;
}
prints
1:
1 1,2,3
5 1,2
----
2:
1 1,2,3
2 2,4
4 2,3
5 1,2
----
3:
1 1,2,3
3 3
4 2,3
----
4:
2 2,4
----
MySQL can't use indices to perform this search, i.e. the query results in a full table scan, see Optimizing Queries with EXPLAIN
edit:
For your second question you only have to change the WHERE-clause to
WHERE FIND_IN_SET('$sql_x', foo)=1

Your data structure in the DB is not optimal for querying the way you want it.
For the first question:
mysql_query("SELECT * FROM table WHERE array LIKE '%,$_GET[id],%' OR array LIKE '$_GET[id],%' OR array LIKE '%,$_GET[id]' OR array = '$_GET[id]'");
For the second:
mysql_query("SELECT id, SUBSTR(array, 1, POSITION(',' IN array) - 1) AS array FROM table WHERE array LIKE '$_GET[id],%' OR array = '$_GET[id]'");
As you can see, these queries aren't pretty, but they'll do what you want.

Untested, but you should be able to use:
Question 1:
SELECT * FROM table WHERE array REGEXP '(^|,)?(,|$)';
// Match either the start of the string, or a , then the query value, then either a , or the end of the string
Question 2:
SELECT * FROM table WHERE array REGEXP '^?(,|$)';
// Match the start of the string, then the query value, then either a , or the end of the string
Where ? is replaced with your $_GET value.
No idea on the performance of this.

I'd recommend you to bring your database to the first normal form, e. g.
CREATE TABLE t_master (
id INT PRIMARY KEY AUTO_INCREMENT
);
CREATE TABLE t_array (
id INT PRIMARY KEY AUTO_INCREMENT,
master_id INT NOT NULL,
value INT,
CONSTRAINT fk_array_master_id FOREIGN KEY (master_id) REFERENCES t_master (id)
);
Then you can find records in t_master that have a specific value with
$q = 'SELECT m.* ' .
'FROM t_master AS m INNER JOIN t_array AS a ON a.master_id = m.id ' .
"WHERE a.value = '" . mysql_real_escape_string($_GET['id'], $db) . "' " .
'GROUP BY m.id';
The most important advantage is that if you have a lot of values, you can add an index to find them much faster:
ALTER TABLE t_array ADD INDEX idx_value (value);
A less evident, but not the last advantage is that your queries become more logical and structured.

If you can't normalise your schema (which is the best option:
SELECT *
FROM table
WHERE ','+array+',' LIKE '%,$_GET[id],%'
But if you need to access the records by id, then you really should normalise

First One:
SELECT * FROM table WHERE array LIKE '$_GET[id],%' OR array LIKE '%,$_GET[id],%' OR array LIKE '%,$_GET[id]' OR array = '$_GET[id]
Second One:
SELECT * FROM table WHERE array LIKE '$_GET[id],%' OR array = '$_GET[id]
Explanation:
'$_GET[id],%' will match, if array is start with $_GET[id]
'%,$_GET[id],%' will match, if $_GET[id] is between any two of array items
'%,$_GET[id]' will match, if array is end with $_GET[id]
array = '$_GET[id]' match, if the array contains only one item equal to $_GET[id]

Related

select rows where same column values start with string, 2 questions

I'm trying to get multiple sums of rows, each sum has a matching column string value, and all the values have a matching 4 character prefix, but it's not working and I could use some help. Also, would CASE be a more or less costly query on the db?
Started with this:
$sql =
"SELECT col1
FROM table
WHERE substr(col1,1,5)='$string'";
$query = mysqli_query($con, $sql);
$row = mysqli_fetch_array($query,MYSQLI_ASSOC);
$results = $row['col1'];
$sum1 = count(array_keys($results,'string1'));
$sum2 = count(array_keys($results,'string2'));
Does it work to get the results from the same column that's in the WHERE clause?
In practice, col1 has row values like aaaa_string1, aaaa_string1, aaaa_string2, aaaa_string2, bbbb_string8... so I'm looking to get all col1 results that have the aaaa in an array, then subsequently filter how many exist of each string1 and string2.
Use SUBSTR(col1, LENGTH('$string')+1) to get the part of the column after the prefix, and group by this.
Use LIKE 'prefix%' to match a column beginning with a prefix.
SELECT SUBSTR(col1, LENGTH('$string')+1) AS suffix, COUNT(*) as count
FROM table
WHERE col1 LIKE '$string%'
GROUP BY suffix
Then you can use a loop to create an associative array with all the counts:
$counts = array();
while ($row = mysqli_fetch_assoc($query) {
$counts[$row['suffix']] = $row['count'];
}
var_dump($counts);
Looking at you code seems that you are trying to get the cout for substring 'string1' or 'string2' in col1
"select col1, count(*) as col_count
from table
WHERE substr(col1,1,5)= '$string'
and col1 in ('string1','string2')
group by col1"
You should retrive the result in col_string and col_count
for suffix (assuming char 6 to end)
"select bstr(col1, 6, 100), count(*) as col_count
from table
WHERE substr(col1,1,5)= '$string'
and substr(col1, 6, 100) in ('string1','string2')
group by bstr(col1, 6, 100)"

mysql select multiple values from array match

I have an array lets say: Array ( [0] => 9 [1] => 7 [2] => 8 )
I want to SELECT from a table (users) all phone numbers where userID matches one from the array (if there is a phone number listed).
I want to do this without selecting all of the users from the database and only those that match that of the array and with actual phone numbers, should I do this in a loop?
Typically when I am doing an UPDATE, I do them within a foreach loop. Like so:
foreach($userArr as $user) {
$pid = $user;
if(!$statement->execute()) {
throw new Exception($statement->error, $statement->errno);
}
}
$statement->close();
Can we do SELECT like that as well?
Thanks in advance for any advice.
If you want to select all these users, just do the follow:
$idList = implode(',', $yourArray);
$sql = "SELECT * FROM users WHERE id IN($idList)";
// execute this $sql query
Try this:
<?php
$array = array(9, 7, 8);
$query = "SELECT * FROM mytable WHERE id = ";
$condition = implode(' OR id = ', $array);
$query .= $condition;
echo $query;
?>
Output:
SELECT * FROM mytable WHERE id = 9 OR id = 7 OR id = 8
You should do the following:
Build a string to express the userid seperated by comma. - Loop will be needed. i.e id1, id2, id3
Build the query string to search for them.
Example:
SELECT * FROM `Users` WHERE id IN (id1, id2, id3)

MySql NOT IN many values from the mysql fetched result

I have 2 MySql queries which are interdependent.
My 'table1'
----------
id
----------
1
2
3
4
5
6
7
My First query
$sql1 = "SELECT * FROM table1 WHERE";// some condition which gives me id's 1,2,3
$res1=$obj->_executeQuery($sql1);
$res1=$obj->getAll($res1);
The result of this is giving me array
Array
(
[0] => Array
(
[id] => 1
..
..
)
[1] => Array
(
[id] => 2
..
..
)
[2] => Array
(
[id] => 3
..
..
)
)
I want to run another query on same 'table1', where not equal to list of ID's which i am getting from the first query.
My Second Query
$sql2 = "SELECT * FROM table1 WHERE id NOT IN (" . implode(',', $res1) . ")";
This is not showing me only one id i,e first. In above case i should get id's 4,5,6,7
Since implode will not give the desired value on multidimensional array so first you need to get the array of all id's to form one-dimensional array then use implode on the array of id's:
$id=array();
foreach ($res1 as $key=>$inner_array){
$id[]= $inner_array['id'];
}
you can use array_walk also here like this:
array_walk($res1,function($c) use (&$id) {$id[] = $c['id'];});
but i think the best one is array_map :
$id = array_map(function($i) {
return $i['id'];
}, $res1);
$sql2 = "SELECT * FROM table1 WHERE id NOT IN (" . implode(',', $id) . ")";
Note: when ever you are doing select please specify your column if you need few to select,unnecessarily selecting all will slow your sql processing.
suppose here:SELECT * FROM table1 WHERE, if you need only id then please select id only.
You have to change $res1, which is a two-dimensional array, into a one-dimensional array of IDs to be able to use implode:
$ids_from_first_query = array();
foreach($res1 as $result_row) {
$ids_from_first_query[] = $result_row['id'];
}
$ids_as_string = implode(',', $ids_from_first_query);
$sql2 = 'SELECT * FROM table1 WHERE id NOT IN(' . $ids_as_string . ')';
In the above code, $ids_as_string will look like this:
1,2,3
Thus it can be used in your MySQL query
Here you are getting two dimensional array so that's reason it is not working
while($each=mysql_fetch_array($res1))
{
$array[]=$each[id];
}
$imp=implode(",",$array);
$sql2 = "SELECT * FROM table1 WHERE id NOT IN (".$imp.")";
Try this it will works

PHP - return SQL GROUP BY as array?

I'm trying to return a MySQL query using GROUP BY as a array.
My table looks like this:
user_id | type
--------------------
1 | test
1 | test
2 | test
1 | hello
1 | helloworld
And my code and query:
$number_of_workouts = array();
$query = mysqli_query(connect(),"SELECT type, COUNT(*) FROM `log` WHERE `user_id` = $user_id GROUP BY type");
$number_of_workouts = mysqli_fetch_assoc($query);
return $number_of_workouts;
This code above isn't returning a array with all types listed, it will only return the number of one type(assuming that $user_id = 1.
How can I return the result of the query as an array?
mysqli_fetch_assoc($query);
fetches 1 row only from the resultset
If you want ALL rows from the resultset, you have to loop for each row and add it to a stack like:
$number_of_workouts = array();
$query = mysqli_query(connect(),
"SELECT type, COUNT(*) AS count
FROM `log`
WHERE `user_id` = $user_id
GROUP BY type"
);
$array = array();
while ($number_of_workouts = mysqli_fetch_assoc($query)) {
$array[$number_of_workouts['type']] = $number_of_workouts['count'];
}
// Now you have all results like you want in the variable array:
print_r($array);
// print count of type test:
echo $array['test'];
Or you try out mysqli_fetch_all() (http://www.php.net/manual/en/mysqli-result.fetch-all.php)
(sorry for many updates)
You are fetching only first record here. Keep the fetching statement in while loop
while($number_of_workouts = mysqli_fetch_assoc($query))
{
echo "<pre>";
print_r($number_of_workouts);
}

MySQL Count in PHP while loop only returns one result then Null

Ok, so I have some MySQL tables as follows:
Buildings
Building-ID Building-Name
===========----=============
1 Building-1
2 Building-2
3 Building-3
4 Building-4
Building-1
Mroom State
=====----======
1 Booked
2 Empty
3 Empty
4 Empty
Building-2
Mroom State
=====----======
1 Booked
2 Empty
3 Empty
4 Empty
And a query in PHP as follows (Ignore the hard coded while, I've simplified the code a bit):
$sql = "select * from Buildings";
$result = mysql_query ($sql) or die(mysql_error());
while ($row = mysql_fetch_array($result))
{
$building[] = $row['ward_name'];
}
$v1 = 0;
while ($v1 < 4)
{
$sql = "SELECT COUNT(*) FROM `$building[$v1]` WHERE state = 'Empty'";
$result = mysql_query($sql) or die(mysql_error());
$count = mysql_result($result, 00);
var_dump($count[$v1]);
$v1 = $v1 + 1;
}
To my way of thinking this should create an array of the buildings contained in the "Buildings" table, start a loop, load the building name from the array and provide a row count for the table of how many rows contain "Empty" in the state column. What it actually does is provide a count for the first table and then provides "NULL" for the rest.
I'd appreciate any help you can give me.
Cheers!
What about changing your data model?
Table buldings can be kept as is:
Buildings
Building-ID Building-Name
===========----=============
1 Building-1
2 Building-2
3 Building-3
4 Building-4
New table:
Rooms
Building-ID Mroom State
===========-=====-=====
1 1 1
1 2 0
2 1 0
State 0 = Empty, State 1 = Booked
Then use a join with group by:
select count(*) from buildings b inner join rooms r on r.bid = b.id where r.state = 0 group by b.id;
Then you will get a row for each building with the count of empty rooms. You won't need a table for each building.
This does noit make sense:
$count = mysql_result($result, 00);
var_dump($count[$v1]);
you mean to write:
$count[$v1] = mysql_result($result, 00);
var_dump($count[$v1]);
Also do not use several tables with names matching columns of other tables.
You can use one table with a primary key that spans two columns instead, for example create primary key on($buildingid,$roomid)
so that the table has columns $buildingid,$roomid, and $state.
mysql_result() returns a string, not an array.
Modify the code and check that now it works as expected.
var_dump($count);

Categories