Selecting and updating any number of rows in large table using CodeIgniter - php

I've got a large table, about 10 million rows, and I'm trying to build a function that selects a random number of rows (anything between 1 and all), updates a field on the selected rows to x (winner) and updates the field on remaining rows to y (loser).
All rows have a unique id but not all rows will be selected from (the table has competition entries for a number of competitions but the function needs to select winners for one competition only).
I've considered ordering by random but it's too slow for a big table.
I've also considered assigning a random value into the row when it's inserted into the table so that it can be used to order but it would have to be unique and there can be batch updates for thousands of rows so it would be slow to assign a unique random value to each row.
There's too much data to save the result as an array and shuffle.
Can anyone suggest other solutions?
This is how I would do it if the table wasn't huge:
function getWinnersLosers($winnercount,$allwinners) {
// Must have draw id and ticketstatus id
if ( ! $this->draw_id || ! $this->ticketstatus_id ) return false;
// Update winners
$this->db->where('draw_id', $this->draw_id);
$this->db->where('ticketstatus_id', CONST_TICKETSTATUS_ENTERED);
$this->db->order_by('id', 'RANDOM');
if ( ! $allwinners ) $this->db->limit($winnercount);
$data = array( 'ticketstatus_id' => CONST_TICKETSTATUS_WINNERUNCLAIMED );
$query = $this->db->update('drawtickets',$data);
// Update losers (remaining tickets)
$this->db->where('draw_id', $this->draw_id);
$this->db->where('ticketstatus_id !=', CONST_TICKETSTATUS_WINNERUNCLAIMED);
$data = array( 'ticketstatus_id' => CONST_TICKETSTATUS_LOSE );
$query = $this->db->update('drawtickets',$data);
}

Related

Randomly select multiple rows and randomly update multiple rows between 2 tables (Laravel eloquent)

I have a situation like this
My mysql has 2 tables product_queue and description
I want to randomize multiple rows of content of column 'content' in descripton table to randomly update multiple rows into 'descripton' column of product_queue table provided that store_id column of 2 tables must be equal
Image description table
Image Product_queue table
I tried this code but it didn't
$descriptions = DescriptionModel::orderByRaw("RAND()")->get();
foreach ($descriptions as $description) {
ProductQueue::where('store_id', $description->store_id)
->update(['description' => $description->content]);
}
Before I ask a question, I have also tried on the forum
use this to get random records from db
$data = DB::table('table_name')->inRandomOrder()->limit(50)->get();
Try this:
$descriptions = DescriptionModel::inRandomOrder()->get();
$descriptions = DescriptionModel::inRandomOrder()->limit(20)->get(); // get 20 random records
or:
$descriptions = DescriptionModel::all()->random();
$descriptions = DescriptionModel::all()->random(20); // get 20 random records

Get SUM form last 2 rows input with laravel

i have table like this:
enter image description here
i want get sum from field 'total' from last 2 rows input,
this my code :
$data = DB::table('packagings')->where('plant',$pt->plant)->orderBy('id','desc')->limit(2)->sum('total');
but my code get all sum from field 'total'
Mysql will sum total from table packagings firstly that will become one record, and then take 2 records from one record. So it always return all sum from field total.
Collection way:
$data = DB::table('packagings')->where('plant',$pt->plant)->latest()->take(2)->get()->sum('total');
Query Builder way:
$sub = DB::table('packagings')->where('plant',$pt->plant)->latest()->take(2);
$data = DB::table(DB::raw("({$sub->toSql()}) AS sub"))->mergeBindings($sub)->sum('total');

PHP increment statement according to value in database

I have created a PHP form with values that are inserted in the database. Fields dropdown boxes that are passed to the database after submit. According to what the user chooses in the dropdown box, score increases.
It contains age (dropdown box, >20 <20), degree (high school, university), etc.
What I want to build,is a function to add score values according to the choice of the dropdown box. Make specific column values a variable which adds scores points.
Every time someone inserts a specific choice, it should get a different amount of points.
Pseudocode, for score:
i = 0.
If dropdown.age>20 (choice 1), 5 points, i= i +5.
If dropdown.age<20, 10 points, i= i +10
If dropdownchoicebox.education = high school, 5 points, if university, 10 points.
Same for database
If age-row.value>20, i +5 else i+10
if education-row.value = highschool, i= i+5 else i + 10
And it should continue giving "score points", according to each specific choice in every field.
The code so far shows the database values. Each insert is in a different row until it runs out rows. For instance, age would be row 4, education row 5, etc.
<?php
// Get a db connection.
$db = JFactory::getDbo();
// Create a new query object.
$query = $db->getQuery(true);
// Select all records from the user profile table.
// Order it by the ordering field.
$query->select($db->quoteName(array(age, education, FieldName, FieldValue)));
$query->from($db->quoteName('table'));
// Reset the query using our newly populated query object.
$db->setQuery($query);
$row = $db->loadRow();
print_r($row);
// Load the results as a list of stdClass objects (see later for more options on retrieving data).
$results = $db->loadObjectList();
?>
Result: array value
Array ( [0] => over 20 [1] => highschool [2] => result 2[3] => result3
Names of rows: [0] = age, [1] = education.
What I want to do:
Button onclick: calculate points
function calculate points
//i for score
i=0
As 0 = over 20, i=0+5 = 5
as 1 = highschool i= 5+5 = 10

Codeigniter Join Table to Showing Different Content Results

I have 7 tables to store user data such posts, images, updates, comments, likes, reposts and user itself.
And here is my questions: How to using right query to execute join table?
I'm using this query:
if ( ! function_exists('getTimeline'))
{
function getTimelines($contributor = null, $limit = 10, $offset = 0)
{
$CI =& get_instance();
$CI->db->select('
abycms_posts.*,
abycms_images.imageID,
abycms_images.contributor as owner,
abycms_images.imageContent,
abycms_images.imageFile,
abycms_images.imageSlug,
abycms_images.timestamp as date,
abycms_images.visits_count as visits,
abycms_updates.updateID,
abycms_updates.userID as updater,
abycms_updates.updateContent,
abycms_updates.visibility,
abycms_updates.timestamp as update_time,
abycms_likes.likeID,
abycms_likes.userID as userLike,
abycms_likes.type as likeType,
abycms_likes.timestamp as like_time,
abycms_comments.commentID,
abycms_comments.userID as commentUser,
abycms_comments.type as commentType,
abycms_comments.timestamp as comment_time,
abycms_reposts.repostID,
abycms_reposts.userID as repostUser,
abycms_reposts.type as repostType,
abycms_reposts.timestamp as repost_time
');
$CI->db->from('abycms_users');
$CI->db->join('abycms_posts', 'abycms_posts.contributor = abycms_users.userID', 'left');
$CI->db->join('abycms_images', 'abycms_images.contributor = abycms_users.userID', 'left');
$CI->db->join('abycms_updates', 'abycms_updates.userID = abycms_users.userID', 'left');
$CI->db->join('abycms_likes', 'abycms_likes.userID = abycms_users.userID', 'left');
$CI->db->join('abycms_comments', 'abycms_comments.userID = abycms_users.userID', 'left');
$CI->db->join('abycms_reposts', 'abycms_reposts.userID = abycms_users.userID', 'left');
$CI->db->where('abycms_users.userID', $contributor);
$CI->db->limit($limit, $offset);
// How to order results by newest `timestamp` for posts, images, updates, comments, likes or reposts?
$CI->db->order_by('abycms_posts.timestamp', 'desc');
// How to handle not duplicate `postID` or `imageID` also group it by different `type`s?
$CI->db->group_by('abycms_posts.postID, abycms_images.imageID');
$query = $CI->db->get();
if($query->num_rows() > 0)
{
return $query->result_array();
}
else
{
return array();
}
}
}
And there is my view to handle results in different type:
foreach(getTimelines($page['userID'], $limit, $offset) as $row)
{
if($row['updateID'] != null) // Updating Status
{
// This status updates
}
elseif($row['postID'] != null) // Writing Article
{
// This is posts
}
elseif($row['imageID'] != null) // Uploading Image
{
// This is images
}
elseif($row['commentID'] != null) // Commented on Post
{
// This is comments
}
elseif($row['likeID'] != null) // Liking User Post
{
// This is likes
}
elseif($row['repostID'] != null) // Reposting User Post
{
// This is reposts
}
}
When i'm using above query, results is showing up but i have no idea to separate content types. It always shown as status updates, and all unique id such postID, imageID, updateID, repostID, likeID and commentID have same value.
The query is generating a partial cross product.
For every row returned from _users, MySQL is getting all of the matching rows from _likes.
For sake of an example, we'll assume that there is one row being returned from _users, and there are four matching rows in _likes, returning (so far) a total of four rows. The row from _users gets matched to each of the four rows from _likes. All of the columns from the row from _users is duplicated into each of the four rows.
And from the _posts table, for the sake of an example, we'll assume that there are two rows that match. So each of those two rows returned from _posts is going to matched to each of the four rows we already have, giving us a total of eight rows. (Every row returned from _posts is matched with every row returned from _likes.)
From the _comments table, for this example, let's say there are six rows returned. Each of those rows gets matched with the eight rows we already have, giving us a total of 48 rows. And a lot of values from the columns of each table is getting "duplicated" into new rows, as multiple rows from the new tables are joined in.
And so on, with each additional joined table.
It's a partial "cross product" of the tables. (A semi-Cartesian product?)
If you want to return distinct list of _posts, a distinct list of _likes, and distinct list of _comments, etc. then you could run a separate query for each table. That would avoid the "duplication" that happens due to the join operation. That's probably the simplest approach.
Otherwise, if you want to get a distinct list of _posts, _likes, _comments, et al. out of the resultset the current query is returning, you'd need the client to sift through the rows to filter out the duplicated _posts, _likes, _comments. You'd need to have a unique identifier for each of those tables included in the returned rows.
Basically, your code would need to build separate arrays for _posts, _likes, _comments. For each row from the resultset, you'd need to check whether the values from the _posts columns were from a row from _posts you've already processed. If it's one you've already processed, discard it, otherwise, add it to the array. Essentially de-duplicating the rows down into separate results from each table, in the form that you'd get from a separate query of each table.

need help to find a php structure solution

I am just a student at php, I am trying to find out a list of members from a table where I dont know how much rows are in that table, but I need every 6 rows on Order By entrytime DESC basis.
My table structure is as below:
int `ID`
int `entrytime` // this time updates when rows insert
now I need to find out all ids on basis of entrytime DESC and insert those ids in a separate new table say "new_tbl" as a group of 6 ids
ind `ID`
varchar `group_name`
I am trying to do like this :
$qry=mysql_query("SELECT id FROM main_table entrytime ASC");
while($res=mysql_fetch_row($qry)){
$id=$res['0'];
$q=mysql_query();
######### But not getting any Idea how to find every 6 Ids and insert in new_tbl #######
}
In your case you use mysql_fetch_row this gives you the count of rows and not the data.
while($res=mysql_fetch_assoc($qry)) {
To get the Data you have to use mysql_fetch_assoc for example.
To find every 6 Ids you can make a counter and increment the value by 1. If the modulo of 6 and the value is 0 you have the sixth value and you can reset the counter.
$i = 1;
while ...
if($i % 6 == 0) {
// reset your counter
$i = 1;
}
$i++;
}
Then you can use the counter to work with it and write that to another table for example.

Categories