This question already has answers here:
how to select unique keywords from a comma separated tags
(3 answers)
Closed 5 months ago.
This is my table tracks:
+---+--------------------+
| id| tag|
+---+--------------------+
| 1 | dance,|
| 2 | dance,tecno,|
| 3 | dance,hihop,|
| 4 | rap,|
| 5 | country,|
| . | ...|
+---+--------------------+
I tried this ($value is my query):
$tags = $this->db->query(sprintf("SELECT `tag`, `id` FROM `tracks` WHERE `tag` LIKE '%s' GROUP BY `tag` DESC LIMIT %s, %s", '%'.$this->db->real_escape_string($value).'%', $this->db->real_escape_string($start), $per_page));
while($row = $tags->fetch_assoc()) {
$rows[] = $row;
}
$tags = explode(',', $row['tag']);
$rows = array_unique(array_map('strtolower', $tags));
foreach($rows as $row) {
if(stripos($row, $value) !== false) {
$tag_output .= '<div class="hashtag-inner">
'.$row.'
</div>';
}
}
From this Eg. the output expected was: dance, tecno, hiphop, rap, country with all unique tags instead I have multiple output for the tag dance.
What's wrong with my output?
You need to call explode() in the loop that processes each row. Your code is just exploding the last row.
$rows = array();
while ($row = $tags->fetch_assoc()) {
$tags = explode(',', $row['tag']);
$rows = array_merge($rows, $tags);
}
$rows = array_unique(array_map('strtolower', array_filter($rows)));
array_filter() is used to remove the empty strings that come from the , at the end of the tag lists.
However, the best long-term solution would be to normalize your database schema so you don't store comma-separated lists in the table. You should have a table where each tag is in a separate row.
I think you need something like this
$tags = $this->db->query(sprintf("SELECT `tag`, `id` FROM `tracks` WHERE `tag` LIKE '%s' GROUP BY `tag` DESC LIMIT %s, %s", '%'.$this->db->real_escape_string($value).'%', $this->db->real_escape_string($start), $per_page));
$str = '';
while($row = $tags->fetch_assoc()) {
// combine all tags from "tag" column
$str .= $row['tag'];
}
$tags = explode(',', $str);
$rows = array_unique(array_map('strtolower', $tags));
foreach($rows as $row) {
if(stripos($row, $value) !== false) {
$tag_output .= '<div class="hashtag-inner">
'.$row.'
</div>';
}
}
Related
I want to find a value from a column which has multiple values like (23,24,25), Using php mysqli query.
Table:
+-----------------+
id | tag_ids |
+-----------------+
1 | 3,4,5 |
2 | 3,7,8,9 |
3 | 4,5,10 |
Curent query:
$value = '3';
$query = "SELECT tag_ids FROM table WHERE FIND_IN_SET($value, tag_ids)";
$result = mysqli_query($query);
$count = mysqli_num_rows($result);
echo count;
Result will be: YES/NO or 1/0, if the Given value is match any value with tag_ids.
I found the result my self and here is code:
function statusvalues() {
$query = "SELECT tag_ids FROM tblname WHERE tag_ids !=''";
$result = mysqli_query($query, DBCONN);
$idarray = array();
while($row = mysqli_fetch_array($result)) {
array_push($idarray, $row['tag_ids']);
}
return $idarray;
}
function status($ID) { //Passing tag id
$set_of_numbers = statusvalues();
$reset_numbers = implode(", ", $set_of_numbers);
$values = explode(", ", $reset_numbers);
if (in_array($ID, $values)){
return "disabled";
}
}
this is MySQL table structure:
TABLE: products
|----------------------------------------------|
| id | product_ids |
| 1 | 51 |
| 2 | 616,2,38 |
| 3 | (NULL) |
| 4 | 426,605,604 |
|----------------------------------------------|
What im looking is a way for the code to check if the id 605 exists in product_ids row, and if it does to replace for another ID:
any idea how can i accomplish this?
I was thinking of a sql QUERY...
$sql = "SELECT * FROM products";
$r1=$con->execute_query($sql);
while ($row1 = mysql_fetch_array($r1, MYSQL_ASSOC)) {
if($row1['product_ids']) {
$data = preg_split('/,/', $row1['product_ids']);
if(is_array($data)) {
foreach($data as $key => $value) {
if($value == 605) {
echo $value;
}
}
}
}
}
Check it out on CodePad
This is the best http://dev.mysql.com/doc/refman/5.0/en/string-functions.html#function_find-in-set for denormalization problem
while ($row1 = mysql_fetch_array($r1, MYSQL_ASSOC)) {
if($row1['product_ids']){
$val_changed = false;
$prod_ids = $row1['product_ids'];
$ids = explode(',', $prod_ids);
for($i = 0; $i < count($ids); $i++) {
if($ids[$i] === '605') {
$ids[$i] = $new_id;
$val_changed = true;
}
}
if($val_changed) {
$prod_ids = implode(',', $ids);
//update db with new value $prod_ids
}
}
}
To get only records that have the id you're looking for, and use preg_replace to change the value, and update the table with the new value
$new_id = '999';
$new_val = preg_replace('/,605,/', $new_id, $row1['product_ids']);
Query with Regex (Fancy!):
SELECT * FROM products WHERE product_ids REGEXP '^[^0-9]605[^0-9]$';
Script to modify data:
while( $row1 = mysql_fetch_array( $r1, MYSQL_ASSOC ) )
{
$product_ids = explode( ',', $row1['product_ids'] );
if( ( $key = array_search( '605', $product_ids ) ) !== FALSE )
{
$product_ids[$key] = $new_id_number;
$product_ids = implode( ',', $product_ids );
// Enter Code to Update Table Here
}
}
To find out if it contains '605':
SELECT id, product_ids FROM products
where product_ids REGEXP '^.*[^\d]605(?!\d).*$'
Comment: this is, by the way, a very good example why we shouldn't use multiple values in the same field!
Now once you have it - you can do whatever you want, you can play with it:
$new_product_ids = preg_replace('/^(.*[^\d])(605)(?!\d)(.*)$/','${1}new_id${3}',$row1['product_ids']);
and update the row:
update products set product_ids = '$new_product_ids' where id = $id
I have a string containing comma separated keywords. For Example:
$keywords = 'keyword1, keyword2, keyword3';
My Table schema, named tbl_address is like this ( simplified ) :
id INT(11) PRIMARY KEY, AUTO INCREMENT
address VARCHAR(250) NOT NULL
Assume I have to use MySQLi in PHP ( not PDO ).
Here is my current approach:
$result = array();
$keyword_tokens = explode(',', $keywords);
foreach($keyword_tokens as $keyword) {
$keyword = mysqli_real_escape_string(trim($keyword));
$sql = "SELECT * FROM tbl_address WHERE address LIKE'%$keyword%'";
// query and collect the result to $result
// before inserting to $result, check if the id exists in $result.
// if yes, skip.
}
return $result;
This approach works, but inefficient in performance. If there are a lot of keywords, it will make a lot queries.
My question is, is there a better way to achieve the same goal ? i.e. what is the simplest way to return all records with the address containing the ANY of the keywords ?
A simple REGEXP might be what you're after. You'd have to check how efficient it is for yourself.
SELECT * FROM tbl_address WHERE field REGEXP 'keyword1|keyword2|keyword3';
SELECT * FROM user;
+---------+----------+
| user_id | username |
+---------+----------+
| 101 | Adam |
| 102 | Ben |
| 103 | Charlie |
| 104 | Dave |
+---------+----------+
SELECT *
FROM user
WHERE FIND_IN_SET(username,'adam,ben,dave') > 0;
+---------+----------+
| user_id | username |
+---------+----------+
| 101 | Adam |
| 102 | Ben |
| 104 | Dave |
+---------+----------+
You only need an 'OR', nothing else...
<?php
$result = array();
$keyword_tokens = explode(',', $keywords);
$keyword_tokens = array_map('mysqli_real_escape_string', $keyword_tokens);
$sql = "SELECT * FROM tbl_address WHERE address LIKE'%";
$sql .= implode("%' or address LIKE '%", $keyword_tokens) . "'";
// query and collect the result to $result
// before inserting to $result, check if the id exists in $result.
// if yes, skip.
return $result;
edit: Just to be sure you also trim the keywords
<?php
$result = array();
$keyword_tokens = explode(',', $keywords);
$keyword_tokens = array_map(
function($keyword) {
return mysqli_real_escape_string(trim($keyword));
},
$keyword_tokens
);
$sql = "SELECT * FROM tbl_address WHERE address LIKE'%";
$sql .= implode("%' OR address LIKE '%", $keyword_tokens) . "'";
// query and collect the result to $result
// before inserting to $result, check if the id exists in $result.
// if yes, skip.
return $result;
Also, you should also pass the db resource link to the mysqli_real_escape_string() function...
The best way is to use fulltext search.
http://dev.mysql.com/doc/refman/5.0/en/fulltext-search.html
if you don't want to use fulltext you can use OR in your WHERE condition
SELECT * FROM tbl_address WHERE address LIKE '%$keyword%' OR adress LIKE '%$keyword2%'
Try WHERE IN clause:
$keyword = (array)explode(',', $keywords);
for($i=0;$i=count($keyword);$i++){
$keyword[$i]=mysqli_real_escape_string(trim($keyword[$i]),'\'" ');
}
//This is what I suggest.
$query='SELECT * FROM tbl_address WHERE address IN ("'.implode('","',$keyword).'")';
Successfully tested on MySQL 5.1.
Make single query
$keywordary = explode(',', $keywords);
foreach($keywordary as $keyword) {
$keys = trim($keyword);
$other .=" or address like '%$keys%'";
}
$sql = "SELECT * FROM tbl_address WHERE address LIKE'%$keyword%' $other";
execute query;
return $result;
Best way is just create search string WHERE clause and append it to query and run it once.
$result = array();
$keyword_tokens = explode(',', $keywords);
$where = '';$i=0
foreach($keyword_tokens as $keyword) {
$where.= " address LIKE'%".mysqli_real_escape_string(trim($keyword))."%' OR ";
}
// trim last OR with substr_replace
substr_replace($where, "OR", -1, 1);
$sql = "SELECT * FROM tbl_address WHERE $where";
return $result;
Hi create a query with union and execute in the end of the loop
$result = array();
$keyword_tokens = explode(',', $keywords);
$sql = '';
foreach($keyword_tokens as $keyword) {
$keyword = mysqli_real_escape_string(trim($keyword));
if (!empty($sql)) $sql .= " UNION ";
$sql .= "SELECT * FROM tbl_address WHERE address LIKE'%$keyword%'";
// query and collect the result to $result
// before inserting to $result, check if the id exists in $result.
// if yes, skip.
}
Execute the query here.
I have a database like this:
+----+---------------------+
| id | tags |
+----+---------------------+
| 1 | test1, test2, test3 |
| 2 | test1, test2, test3 |
| 3 | test1, test2, test3 |
| 4 | test1, test2, test3 |
| 5 | buh1, buh2, buh3 |
+----+---------------------+
Now i want to display the most popular tags from this database. I have a function, and it works with a array like this:
$tag_array = array(
'test1, test2 test, test3',
'test2, test4, test2',
'buh, buh2, buh3' );
The function:
function popularTags($tag_array) {
$p = array();
foreach($tag_array as $tags) {
$tags_arr = array_map('trim', explode(',', $tags));
foreach($tags_arr as $tag) {
$p[$tag] = array_key_exists($tag, $p) ? $p[$tag]+1 : 1;
}
}
arsort($p);
return $p;
}
This is how to display the most popular tags:
foreach(popularTags($tag_array) as $tag=>$num)
{
echo $tag, " (", $num, ")<br />";
}
This works so far, with a normal array.
Now, i want to get the tags from the Database, so i extract the values from the database and run the function like this:
$result = mysql_query("select * from DB ORDER BY date DESC");
while($row = mysql_fetch_array($result)){
$tag_array = $row["$tags"];
foreach(popularTags($tag_array) as $tag=>$num)
{
echo $tag, " (", $num, ")<br />";
}
}
This give me an error though:
Warning: Invalid argument supplied for foreach()
So my question is how to show the most popular tags from the database with this function?
Thanks
My suggestion is that you normalize your database. Then a query like this becomes trivial, as well as much better performing.
select TagID, count(*)
from EntityTag
group by TagID
order by count(*) descending
limit 5
mysql_fetch_array returns all the rows. So do this:
$rows = mysql_fetch_array($result);
foreach($rows as $row) {
$tag_array = $row["tags"]; // note removing the $
foreach(...) {
}
}
This one works for me:
$result = mysql_query("select tags from DATABASE LIMIT 20");
$tags = array();
while ($row = mysql_fetch_array($result)) {
$row_tag_array = split(",", $row[0]);
foreach ($row_tag_array as $newtag) {
asort($row_tag_array);
if (array_key_exists($newtag, $tags)) {
if ($tags[$newtag] < 200) {
$tags[$newtag] = $tags[$newtag] + 20;
}
}
else {
$tags[$newtag] = 100;
}
}
}
foreach ($tags as $tag => $size) {
echo "<a style=\"font-size: $size%;\" href=\"?t=$tag\">$tag</a> ";
}
Thank you for your help though
I am wanting to order my array by how many times a value comes up in that array and also then print only the highest 6 results.
This is what I have at the moment:
$delimiter = " ";
$tags = array();
$sql = mysql_query("SELECT tags FROM share WHERE site_id = $id");
while($result = mysql_fetch_assoc($sql)) {
$tags_new = explode($delimiter, $result['tags']);
$tags = array_merge($tags , $tags_new);
}
Hum... You can do that:
while($result = mysql_fetch_assoc($sql)) {
$tags_new = explode($delimiter, $result['tags']);
foreach($tags_new as $tag){
$tags[$tag]++;
}
}
After, you need to sort by value, using function sort or rsort (desc).
rsort($tags);
Last, you need slice and get only 6 first:
$high_tags = array_slice($tags, 0, 6, true);
Edit: showing key and value:
foreach($high_tags as $key => $value){
echo "{$key}: {$value}";
}
Or just do:
$high_keys = array_keys($high_tags);
var_dump($high_keys);
Bye :)
You can do this in MySQL with the following query:
SELECT tags, COUNT(tags) AS tag_count
FROM share WHERE site_id = $id
GROUP BY tags
ORDER BY tag_count DESC
LIMIT 6;
This will select the top 6 tags with the highest count. You can then loop over them similar to the PHP code you already have.