How select random column value from Mysql database using PHP - php

I'm trying to fetch random column from database using Rand() function.
It's returning random value but many time it is returning duplicate.
This is what my database table look like.
Column
Type
Null
Default
no
int(30)
No
postid
varchar(100)
Yes
NULL
byuser
varchar(32)
Yes
NULL
likeslimit
int(30)
No
createdon
date
No
And this is what my PHP code is.
$query = mysqli_query(
$mysql,
"SELECT postid FROM history ORDER BY Rand() LIMIT 1"
);
if (mysqli_num_rows($query) == 1) {
while ($row = mysqli_fetch_assoc($query)) {
echo $row['postid'];
}
}
I want it to always return random never the same till the end of data reached.

Don't use loop and condition you want only 1 limit try this
$query = mysqli_query(
$mysql,
"SELECT postid FROM history ORDER BY Rand() LIMIT 1"
);
$row = mysqli_fetch_assoc($query)
echo $row['postid'];

This is the way RAND in mysql works and will repeat the results from time to time. But you can achieve such functionality by using mysql with php.
$query = mysqli_query($mysql, "SELECT postid FROM cacheTable WHERE 1 ORDER BY RAND() LIMIT 1");
$row = mysqli_fetch_assoc($query);
$foundId = (int)$row['postid'];
if((int) $foundId === 0) { // NO records left in cacheTable then fill it up again
mysqli_query($mysql, "INSERT INTO cacheTable (postid) SELECT postid FROM history");
$query = mysqli_query($mysql, "SELECT postid FROM cacheTable WHERE 1 ORDER BY RAND() LIMIT 1");
$row = mysqli_fetch_assoc($query);
$foundId = (int) $row['postid'];
}
mysqli_query($mysql, "DELETE FROM cacheTable WHERE postid=".$foundId); // DELETE the record
$query = mysqli_query($mysql, "SELECT * FROM history WHERE postid=".$foundId);
$result = mysqli_fetch_assoc($query);
cacheTable will have only one column - ID (primary key) which will hold the corresponding ID (primary key) from history. cacheTable structure:
|------
|Column|Type|Null|Default
|------
|postid|varchar(100)|Yes|NULL
|-----
cacheTable will fill with all the ids from history table (it will be done once the cacheTable is empty). You will select rand result from the cacheTable and you will delete it then so it will not appear in the next selects. When we are out of records in cache table it will populate again.
NB: this approach has one major drawback - when you have new entries in history table they won't be available in cache table until it is empty and filled again.

This is the code Samir Nabil Suggested :
session_start();
$_SESSION['dupes'] = array();
$query = mysqli_query(
$mysql,
"SELECT postid FROM history ORDER BY Rand() LIMIT 1"
);
if (mysqli_num_rows($query) == 1) {
while ($row = mysqli_fetch_assoc($query)) {
if (!in_array($row['postid'], $_SESSION['dupes'])) {
echo $row['postid'];
$_SESSION['dupes'][] = $row['postid'];
}
}
}

Related

How to update a value by 1 if the new value inserted into the database clashes with value in the database?

I want to update the database of the sort order column to increase its value by one if the the new value inserted into the database clashes with the value that is already in the database. May I know how should I go about doing it? Please help! Thanks!
Below is my code (I am not sure whether am I on the right track):
$result = mysql_query("SELECT sortorder FROM information ORDER BY id ASC;");
if($result >= 1 ){
$i=1;
while ($initialorder = mysql_fetch_assoc($result))
{
$initialorder = $initialorder["sortorder"];
if ($sortorder == $initialorder ){
$result6 = mysql_query("SELECT * FROM information
WHERE `sortorder` = '$sortorder'");
$row6 = mysql_fetch_array($result6);
$removethis1 = $row6['id'];
$result7 = mysql_query("UPDATE information
SET `sortorder`= ((SELECT `sortorder`
FROM (SELECT MAX(`sortorder`) AS
'$initialorder' FROM information) AS '$initialorder') + 1)
WHERE id='$removethis1'");
}
$query = "INSERT INTO `information`
(`id`,`page`,`description`,`status`,`sortorder`,`keyword`,`date_added`)
VALUES
('$id','$title','$description','$status',
'$sortorder','$keyword','$date_added')";
$result = mysql_query($query, $conn);
header('Location: index.php?status=1&title='.$title);
$i++; }
}
You can do this:
INSERT INTO ON `information`
...
DUPLICATE KEY UPDATE
sortorder = '".$sortorder + 1." '

MySQL next and prev record issue

I made this php script and i am tryin to make it to return next and previus row, but there is one problem when i input my id the script return different thing for example :
This is my DB
ID String
1 Test 1
2 Test 2
3 Test 3
4 Test 4
So if i put ./index.php?id=1 this returns the result of id=2 and id=2 => id=3 and so on...
My question is how to fix it to return accurate result not +1. I tried with <= or => operators the result is correct, but then my links doesnt work.
Here is the script
<?php
if(isset($_GET['id']))
{
$id = (int)$_GET['id'];
}else
{
$id = 0;
}
$stmt1 = $db->prepare("SELECT * FROM records WHERE id > ? ORDER BY id ASC LIMIT 1");
$stmt1->bindValue(1,$id);
$stmt1->execute();
$row = $stmt1->fetch();
$stmt2 = $db->prepare("SELECT * FROM records WHERE id < ? ORDER BY id DESC LIMIT 1");
$stmt2->bindValue(1,$id);
$stmt2->execute();
$row = $stmt2->fetch();
echo $row['id'];
echo "<br/>";
echo $row['string'];
?>
I am not sure if the problem as silly as that, but I have no other explanation.
To have your page you need to make 3 selects:
to get current page data
to get prev id
to get next one
But I can see only 2 selects
So, you have to select data for the very page to show
if(isset($_GET['id']))
{
$sql = "SELECT * FROM records WHERE id = ?";
$stm = $db->prepare($sql);
$stm->execute(array($_GET['id']));
} else {
$sql = "SELECT * FROM records ORDER BY id ASC LIMIT 1";
$stm = $db->query($sql);
}
$row = $stm->fetch();
and now you can go for getting prev and next ids
$sql = "SELECT id FROM records WHERE id < ? LIMIT 1";
$stm = $db->prepare($sql);
$stm->execute(array($row['id']));
$prev = $stm->fetchColumn();
$sql = "SELECT id FROM records WHERE id > ? LIMIT 1";
$stm = $db->prepare($sql);
$stm->execute(array($row['id']));
$next = $stm->fetchColumn();
i am tryin to make it to return next and previus row
There is no such thing as "previous" or "next" row in a table. Without explicit ordering, tables must be considered as unordered set of rows. And you shouldn't rely on auto_increment field to be sequentially numbered. For example:
because there was interleaved insert on the table,
because the server is allowed to reuse auto_increment after row deletion.
You probably have to modify your table structure to add a sequence number:
CREATE TABLE tbl (id in primary key not null auto_increment,
sequence_number int unique,
value char(40));
While inserting your data you might rely on something like that:
INSERT INTO tbl (sequence_number, value)
VALUES (SELECT COUNT(*) FROM tbl, ?)
And the query for the "next" and "prev":
SELECT * FROM tbl WHERE sequence_number = ?-1 OR sequence_number = ?+1
ORDER BY sequence_number;

Getting record from another table with id recognition

there are tables artist, track, & etc
in the artist table there is :
id
name
cover
desc
and in the track table there is :
id
name
desc
artistid
so if i goto track.php?id=1 and then they print
id
name
desc
artistid i want to make this show the record from artist table with id recognition
and can you show me how to make multiple filter from recordset. because i have field "pubid" when the value is 1 this mean publish and then if the value is 2 this mean unpublish
sorry bad english
thx u so much
Have a look at SQL Join. In order to only get records which may be published, you'll have to add another WHERE clause. Like:
SELECT name, desc FROM track WHERE id = $id AND pubid = 1;
track.php?id=1
or
track.php?id=1&pubid=1
track.php?id=1&pubid=2
<?php
if (isset($_GET['id'])) {
$artistid = $_GET['id'];
if (isset($_GET['pubid'])) {
$pudid = $_GET['pubid'];
$sql = "select `id`, `name` from `track` where `artistid` = {$artistid} and `pubid` = {$pupid} order by `desc`";
} else
$sql = "select `id`, `name` from `track` where `artistid` = {$artistid} order by `desc`";
$query = mysql_query($sql);
while (($row = mysql_fetch_array($query)) !== false) {
echo $row['name'];
}
}

How can I optimise this mysql/php query?

My page displays an image, and I want to display the previous and next image that is relevant to the current one. At the moment I run the same query 3x and modify the "where" statement with =, >, <.
It works but I feel there must be a better way to do this.
The image id's are not 1,2,3,4,5. and could be 1,2,10,20,21 etc. But if it is much more efficient I am willing to change this.
mysql_select_db("database", $conPro);
$currentid = mysql_real_escape_string($_GET['currentid']);
$query ="SELECT * FROM database WHERE id ='".$currentid."' LIMIT 1 ";
$result = mysql_query($query,$conPro) or die(mysql_error());
$affected_rows = mysql_num_rows($result);
if ($affected_rows==1)
{
$row = mysql_fetch_array($result)or die ('error:' . mysql_error());
$current_id = $row['id'];
$current_header = $row['title'];
$current_description =$row['desc'];
$current_image = "http://".$row['img'];
$current_url = "http://".$row['id']."/".$db_title."/";
$current_thumb = "http://".$row['cloud'];
}
mysql_select_db("database", $conPro);
$query ="SELECT * FROM database WHERE id <'".$currentid."' ORDER BY id DESC LIMIT 1 ";
$result = mysql_query($query,$conPro) or die(mysql_error());
$affected_rows = mysql_num_rows($result);
if ($affected_rows==1)
{
$row = mysql_fetch_array($result)or die ('error:' . mysql_error());
$previous_id = $row['id'];
$previous_header = $row['title'];
$previous_description =$row['desc'];
$previous_image = "http://".$row['img'];
$previous_url = "http://".$row['id']."/".$db_title."/";
$previous_thumb = "http://".$row['cloud'];
}else{
$previous_none = "true"; //no rows found
}
mysql_select_db("database", $conPro);
$query ="SELECT * FROM database WHERE id >'".$currentid."' ORDER BY id ASC LIMIT 1 ";
$result = mysql_query($query,$conPro) or die(mysql_error());
$affected_rows = mysql_num_rows($result);
if ($affected_rows==1)
{
$row = mysql_fetch_array($result)or die ('error:' . mysql_error());
$next_id = $row['id'];
$next_header = $row['title'];
$next_description =$row['desc'];
$next_image = "http://".$row['img'];
$next_url = "http://".$row['id']."/".$db_title."/";
$next_thumb = "http://".$row['cloud'];
}else{
$next_none = "true"; //no rows found
}
mysql_close($conPro);
Thank you for your time
You don't have to do select_db each time. Once you 'select' a db, it stays selected until you select something else.
You can't really get away from doing two separate queries to get the next/previous images, but you can fake it by using a union query:
(SELECT 'next' AS position, ...
FROM yourtable
WHERE (id > $currentid)
ORDER BY id ASC
LIMIT 1)
UNION
(SELECT 'prev' AS position, ...
FROM yourtable
WHERE (id < $currentid)
ORDER BY id DESC
LIMIT 1)
This would return two rows, containing a pseudofield named 'position' which will allow you to easily identify which row is the 'next' record, and which is the 'previous' one. Note that the brackets are required so that the 'order by' clauses apply to the individual queries. Without, mysql will take the order by clause from the last query in the union sequence and apply it to the full union results.
You can get the "previous" one first WHERE id <'".$currentid."' ORDER BY id DESC, and then query for two "above" it: SELECT * FROM database WHERE id >= '".$currentid."' ORDER BY id ASC then it takes only two queries instead of three.

MYSQL match text fields

I have a mysql database with around 1.5 million company records(name, country and other small text fields) I want to mark the same records with a flag (for example if two companies with the same name are in USA then I have to set a field (match_id) equal to say an integer 10) and likewise for other matches. At the moment its taking a long time (days) I feel I am not utilizing MYsql properly I am posting my code below, Is there a faster way to do this???
<?php
//Create the table if does not already exist
mysql_query("CREATE TABLE IF NOT EXISTS proj (
id INT(11) NOT NULL AUTO_INCREMENT PRIMARY KEY ,
company_id text NOT NULL ,
company_name varchar(40) NOT NULL ,
company_name_text varchar(33) NOT NULL,
company_name_metaphone varchar(19) NOT NULL,
country varchar(20) NOT NULL ,
file_id int(2) NOT NULL ,
thompson_id varchar(11) NOT NULL ,
match_no int(7) NOT NULL ,
INDEX(company_name_text))")
or die ("Couldn't create the table: " . mysql_error());
//********Real script starts********
$countries_searched = array(); //To save record ids already flagged (save time)
$counter = 1; //Flag
//Since the company_names which are same are going to be from the same country so I get all the countries first in the below query and then in the next get all the companies in that country
$sql = "SELECT DISTINCT country FROM proj WHERE country='Canada'";
$result = mysql_query($sql) or die(mysql_error());
while($resultrow = mysql_fetch_assoc($result)) {
$country = $resultrow['country'];
$res = mysql_query("SELECT company_name_metaphone, id, company_name_text
FROM proj
WHERE country='$country'
ORDER BY id") or die (mysql_error());
//Loop through the company records
while ($row = mysql_fetch_array($res, MYSQL_NUM)) {
//If record id is already flagged (matched and saved in the countries searched array) don't waste time doing anything
if ( in_array($row[1], $countries_searched) ) {
continue;
}
if (strlen($row[0]) > 9) {
$row[0] = substr($row[0],0,9);
$query = mysql_query("SELECT id FROM proj
WHERE country='$country'
AND company_name_metaphone LIKE '$row[0]%'
AND id<>'$row[1]'") or die (mysql_error());
while ($id = mysql_fetch_array($query, MYSQL_NUM)) {
if (!in_array($id[0], $countries_searched)) $countries_searched[] = $id[0];
}
if(mysql_num_rows($query) > 0) {
mysql_query("UPDATE proj SET match_no='$counter'
WHERE country='$country'
AND company_name_metaphone LIKE '$row[0]%'")
or die (mysql_error()." ".mysql_errno());
$counter++;
}
}
else if(strlen($row[0]) > 3) {
$query = mysql_query("SELECT id FROM proj WHERE country='$country'
AND company_name_text='$row[2]' AND id<>'$row[1]'")
or die (mysql_error());
while ($id = mysql_fetch_array($query, MYSQL_NUM)) {
if (!in_array($id[0], $countries_searched)) $countries_searched[] = $id[0];
}
if(mysql_num_rows($query) > 0) {
mysql_query("UPDATE proj SET match_no='$counter'
WHERE country='$country'
AND company_name_text='$row[2]'") or die (mysql_error());
$counter++;
}
}
}
}
?>
I would go for pure sql solution, something like :
SELECT
GROUP_CONCAT(id SEPARATOR ' '), "name"
FROM proj
WHERE
LENGTH(company_name_metaphone) < 9 AND
LENGTH(company_name_metaphone) > 3
GROUP BY country, UPPER(company_name_text)
HAVING COUNT(*) > 1
UNION
SELECT
GROUP_CONCAT(id SEPARATOR ' '), "metaphone"
FROM proj
WHERE
LENGTH(company_name_metaphone) > 9
GROUP BY country, LEFT(company_name_metaphone, 9)
HAVING COUNT(*) > 1
then loop through this results to update ids.
I'm not sure what your are trying to do, but what I can see in your code is that you are making a lot of searches in arrays with a lot of data, I think your problem is your PHP code and not SQL statements.
you will need to adjust the group by fields to suit your matching requirements
if your script times out (quite likely due to the large amount of data), set_time_limit(0)
otherwise you can also add a limit of 1000 or something to the $sql, and run the script multiple times as the where clause will exclude any matched rows already processed (but will not keep track of $match_no inbetween calls, so your would need to handle that yourself)
// find all companies that have multiple rows grouped by identifying fields
$sql = "select company_name, country, COUNT(*) as num_matches from proj
where match_no = 0
group by company_name, country
having num_matches > 1";
$res = mysql_query($sql);
$match_no = 1;
// loop through all duplicate companies, and set match_id
while ($row = mysql_fetch_assoc($res)) {
$company_name = mysql_escape_string($row['company_name']);
$country = mysql_escape_string($row['country']);
$sql = "update proj set match_no = $match_no where
company_name = '$company_name', country = '$country';
mysql_query($sql);
$match_no++;
}

Categories