Laravel pagination showing duplicate and replacing random row - laravel-5.4

I am using laravel 5.4 with pagination and I have an issue where a row from my database shows up twice, once on two out of the 4 pages. When I delete the row however both are removed but the total count of rows using the count only shows -1 and then I see a previously hidden/replaced row.
See data below:
Straight from Database, query is set up to show all of these rows +
Query:
SELECT *
FROM `faulty_device`
WHERE `fault_id` = 14
AND `status` < 3
(Bold is precented twice in laravel and cursive is not showing at all)
|4254|11383|14|NULL|XXXXXXXXXX|1|NULL|2017-05-05 07:07:43
|4208|10411|14|NULL|XXXXXXXXXX|1|NULL|2017-05-04 07:16:03
|4207|10313|14|NULL|XXXXXXXXXX|1|NULL|2017-05-04 07:16:03
|4206|10229|14|NULL|XXXXXXXXXX|1|NULL|2017-05-04 07:16:03 (Not showing)
|4205|9527|14|NULL|XXXXXXXXXX|1|NULL|2017-05-04 07:16:03
|4204|8538|14|NULL|XXXXXXXXXX|1|NULL|2017-05-04 07:16:03
|4203|8457|14|NULL|XXXXXXXXXX|1|NULL|2017-05-04 07:16:03
|4202|8454|14|NULL|XXXXXXXXXX|1|NULL|2017-05-04 07:16:03
|4201|8402|14|NULL|XXXXXXXXXX|1|NULL|2017-05-04 07:16:03
|4200|6497|14|NULL|XXXXXXXXXX|1|NULL|2017-05-04 07:16:03
|4199|6454|14|NULL|XXXXXXXXXX|1|NULL|2017-05-04 07:16:03
|4198|6384|14|NULL|XXXXXXXXXX|1|NULL|2017-05-04 07:16:03
|4209|24666|14|NULL|XXXXXXXXXX|1|NULL|2017-05-04 07:16:03
|4241|451|14|NULL|XXXXXXXXXX|1|NULL|2017-05-05 07:07:43
|4242|1526|14|NULL|XXXXXXXXXX|1|NULL|2017-05-05 07:07:43
|4253|9879|14|NULL|XXXXXXXXXX|1|NULL|2017-05-05 07:07:43
|4252|9395|14|NULL|XXXXXXXXXX|1|NULL|2017-05-05 07:07:43
|4251|9277|14|NULL|XXXXXXXXXX|1|NULL|2017-05-05 07:07:43
|4250|6074|14|NULL|XXXXXXXXXX|1|NULL|2017-05-05 07:07:43
|4249|6000|14|NULL|XXXXXXXXXX|1|NULL|2017-05-05 07:07:43
|4248|5770|14|NULL|XXXXXXXXXX|1|NULL|2017-05-05 07:07:43
|4247|4962|14|NULL|XXXXXXXXXX|1|NULL|2017-05-05 07:07:43
|4246|4740|14|NULL|XXXXXXXXXX|1|NULL|2017-05-05 07:07:43
|4245|4734|14|NULL|XXXXXXXXXX|1|NULL|2017-05-05 07:07:43
|4244|4704|14|NULL|XXXXXXXXXX|1|NULL|2017-05-05 07:07:43
|4243|2824|14|NULL|XXXXXXXXXX|1|NULL|2017-05-05 07:07:43
|4197|3910|14|NULL|XXXXXXXXXX|1|NULL|2017-05-04 07:16:03
|4196|3470|14|NULL|XXXXXXXXXX|1|NULL|2017-05-04 07:16:03 (presented twice)
|4195|3357|14|NULL|XXXXXXXXXX|1|NULL|2017-05-04 07:16:03
|4155|2380|14|NULL|XXXXXXXXXX|1|NULL|2017-05-03 06:55:48
|4121|7766|14|NULL|XXXXXXXXXX|1|NULL|2017-05-02 09:43:29
|4120|7561|14|NULL|XXXXXXXXXX|1|NULL|2017-05-02 09:43:29
|4119|7318|14|NULL|XXXXXXXXXX|1|NULL|2017-05-02 09:43:29
|4118|7276|14|8|XXXXXXXXXX|2|NULL|2017-05-02 09:43:29
|4117|6782|14|NULL|XXXXXXXXXX|1|NULL|2017-05-02 09:43:29
|4116|6571|14|NULL|XXXXXXXXXX|1|NULL|2017-05-02 09:43:29
|4115|5713|14|NULL|XXXXXXXXXX|1|NULL|2017-05-02 09:43:29
|4112|4603|14|NULL|XXXXXXXXXX|1|NULL|2017-05-02 09:43:29
|4110|3633|14|NULL|XXXXXXXXXX|1|NULL|2017-05-02 09:43:29
|4106|2805|14|NULL|XXXXXXXXXX|1|NULL|2017-05-02 09:43:29
|4158|4515|14|NULL|XXXXXXXXXX|1|NULL|2017-05-03 06:55:48
|4159|5627|14|NULL|XXXXXXXXXX|1|NULL|2017-05-03 06:55:48
|4160|5628|14|NULL|XXXXXXXXXX|1|NULL|2017-05-03 06:55:48
|4194|2858|14|NULL|XXXXXXXXXX|1|NULL|2017-05-04 07:16:03
|4193|1536|14|NULL|XXXXXXXXXX|1|NULL|2017-05-04 07:16:03
|4192|849|14|NULL|XXXXXXXXXX|1|NULL|2017-05-04 07:16:03
|4168|24642|14|NULL|XXXXXXXXXX|1|NULL|2017-05-03 06:55:48
|4167|10559|14|NULL|XXXXXXXXXX|1|NULL|2017-05-03 06:55:48
|4166|10439|14|NULL|XXXXXXXXXX|1|NULL|2017-05-03 06:55:48
|4165|10142|14|NULL|XXXXXXXXXX|1|NULL|2017-05-03 06:55:48
|4164|10114|14|NULL|XXXXXXXXXX|1|NULL|2017-05-03 06:55:48
|4163|8777|14|NULL|XXXXXXXXXX|1|NULL|2017-05-03 06:55:48
|4162|8513|14|NULL|XXXXXXXXXX|1|NULL|2017-05-03 06:55:48
|4161|7450|14|NULL|XXXXXXXXXX|1|NULL|2017-05-03 06:55:48
|2933|6841|14|NULL|XXXXXXXXXX|1|NULL|2017-04-08 10:55:36
Basically the presented twice row removes the Not Showing row. When I manually change status on that row to 3 or up(Not included in query therefor will not show) the row that is shown twice, the previously hidden row shows once more. It is like this duplicate is a charmelion just taking someones slot randomly..
Laravel pagination presented data + query :
(I am aware this could be made to look prettier, but It is supposed to do the same thing Which it actually is since if i use a count here it will show 55 rows, just like if i did a count on above)
$faultyDevices = FaultyDevice::
where('status', '!=', '3')
->where('status', '!=', '4')
->where('status', '!=', '5')
->where('status', '!=', '6')
->where('status', '!=', '7')
->orderBy('created_at', 'asc')
->paginate(18, ['*'], 'faults_page');
Here below comes a pagination with a max of 60 so that all the rows show on one page instead of being split to 4. Here it shows all rows correctly, just like when doing the raw SQL in the database:
Any ideas how to fix? Surely this has to be a bug, and not my bad code?

This is because there are many records with the same created_at value. To fix this, add a second order by id to remove the duplicated show in pagination:
$faultyDevices = FaultyDevice::
where('status', '!=', '3')
->where('status', '!=', '4')
->where('status', '!=', '5')
->where('status', '!=', '6')
->where('status', '!=', '7')
->orderBy('created_at', 'asc')
->orderBy('id', 'asc')
->paginate(18, ['*'], 'faults_page');

To avoid showing duplicates, add a distinct() clause to your query:
$faultyDevices = FaultyDevice
::distinct()
->where('status', '<>', 3)
->where('status', '<>', 4)
->where('status', '<>', 5)
->where('status', '<>', 6)
->where('status', '<>', 7)
->orderBy('created_at', 'asc')
->paginate(18, ['*'], 'faults_page');

Are you sure that the table isn't being updated as you click to change page? Basically, Laravel is just counting the rows of the full search, and sets offset and limit according to that number and the page you want to display. There cannot be a bug in that part of the job.
But if some new rows have been inserted after the pagination was printed, then when you navigate to the next page, you will see rows from the previous page. It is normal and there's no way to avoid this unless creating a new pagination system based on the id rather than the row count()

Related

Substraction in MYSQL with some condition

I want to do SUM and SUBTRACTION upon certain condition within mysql query
i have try like this,
asuming the $balance= 655.000.000 then total amount inside my_table = IDR 80.000.000 and USD 500.000
$currency_id = 1;
$balance = 655.000.000;
DB::table('my_table as a')
->join('master_currencies as b', 'a.master_currency_id', 'b.id')
->where('a.id', $id)
->selectRaw("SUM(
CASE
WHEN $currency_id = a.master_currency_id THEN $balance - a.amount
ELSE
a.amount
END) AS net_value, b.symbol, b.id as master_currency_id"
)
->groupBy('b.id')
->get();
The code above should give the result
[
{"net_value":"575.000.000","symbol":"IDR","master_currency_id":1},
{"net_value":"500.000","symbol":"USD","master_currency_id":2}
]
but the result i got is
[
{"net_value":"1.885.000.000","symbol":"IDR","master_currency_id":1},
{"net_value":"500.000","symbol":"USD","master_currency_id":2}
]
Note:
Please ignore dots between numbers, in my database i'm not using these dots. it is for inquiry purposes only
If you have more than one row of IDR then it might be a problem with order of operations.
For example say you have to values (100.000.000) and (50.000.000) then for IDR SUM(655.000.000-100.000.000, 655.000.000-50.000.000)=1.160.000.000 and is not the same as 655.000.000-SUM(100.000.000,50.000.000)=505.000.000 the problem being that each row in the group that you aggregate gets a clean $balance.
You could potentially solve this by doing:
$currency_id = 1;
$balance = 655.000.000;
DB::table('my_table as a')
->join('master_currencies as b', 'a.master_currency_id', 'b.id')
->where('a.id', $id)
->selectRaw("
(CASE
WHEN a.id=$currency_id $balance-SUM(a.amount)
ELSE
SUM(a.amount)
END) AS net_value, b.symbol, b.id as master_currency_id")
->groupBy('b.id')
->get();

How to select multiple where conditions using codeigniter?

my table
This is my table i have to display the data using multiple where conditions. First i select using dms_expire_date,for this i got answer and i am using dms_doc_name in where conditions but i didn't got correct result.
I have tired so far.
]
See this picture if i use "or" in "where" i got testie not within this date.but if i use "and" in "where" i didn't got result for dms_expiry_date
See this picture
i don't know how to do this.please help to solve this problem.
SELECT * FROM `dms_document` WHERE dms_expire_date BETWEEN '2020-05-01' AND '2020-07-16' AND dms_doc_name = '' OR dms_category_id = '' OR dms_subcategory_id=''
I have tired in array also but i didn't result.
$this->db->select('*');
$this->db->join('dms_category as C', 'C.dms_category_id = D.dms_category_id', 'left outer');
$this->db->join('dms_sub_category as S', 'S.dms_subcategory_id = D.dms_subcategory_id', 'left outer');
$this->db->where('dms_expire_date >=', $newstart);
$this->db->where('dms_expire_date <=', $newend);
$this->db->where(array('dms_doc_name' =>$docname,'D.dms_category_id'=>$category,'D.dms_subcategory_id'=>$subcategory));
$data['documents']= $this->db->get('dms_document as D')->result_array();
try
SELECT *
FROM dms_document
WHERE dms_expire_date BETWEEN $newstart AND $newend
AND CASE WHEN $docname IS NULL THEN 1 = 1 ELSE dms_doc_name = $docname END
AND CASE WHEN $category IS NULL THEN 1 = 1 ELSE dms_category_id = $category END
AND CASE WHEN $subcategory IS NULL THEN 1 = 1 ELSE dms_subcategory_id = $subcategory END
--
edited. waiting for clearance.
if I get what you mean correctly, it is problem with understanding AND, OR, and the priority with brackets ()
--
if anyone want to use the fiddle, I have created the sample data for this issue
You can write OR using CodeIgniter's or_where() (v3 docs) or orWhere() (v4 docs).
//your initial query
$sql = "SELECT
*
FROM
`dms_document`
WHERE
dms_expire_date BETWEEN '2020-05-01' AND '2020-07-16'
AND dms_doc_name = ''
OR dms_category_id = ''
OR dms_subcategory_id=''";
//building the same query using CI
$this->db->select('*');
$this->db->from('dms_document');
$this->db->where('dms_expire_date >=', '2020-05-01');
$this->db->where('dms_expire_date <=', '2020-07-16');
$this->db->where('dms_doc_name', '');
$this->db->or_where('dms_category_id', '');
$this->db->or_where('dms_subcategory_id', '');
You can confirm the query this generates by running $this->db->_compile_select(); or $this->db->last_query(); (https://stackoverflow.com/a/6145021/1499877 for reference).
echo '<pre>';
var_dump($sql);
var_dump($this->db->_compile_select());
echo '</pre>';
die();

Codeigniter join, group by and count a row from one table

I'm struggling a bit with this code to get the count result from book_listing (totally) which is the total count of bookings. From the result, some are correct but some are multiplied by 3 or so.
Here is my code:
$this->db->where('list_status', 1)
->where('list_date >=', date('Y-m-d'))
->order_by("user_listings.list_created", "desc")
->limit(18, null)
->select('*, COUNT(user_bookings.book_listing) as totally')
->from('user_listings')
->join('user_images', 'user_images.img_listing = user_listings.list_reference')
->join('user_states', 'user_states.state_id = user_listings.list_state')
->join('user_bookings', 'user_bookings.book_listing = user_listings.list_reference', 'left')
->group_by('user_listings.list_reference')
->get();
Thanks to any help :)
So I solved it, the user_images table seems to be causing the issue due to multiple images being fetched while I need it to return only one.
$this->db->where('list_status', 1)
->where('list_date >=', date('Y-m-d'))
->order_by("user_listings.list_created", "desc")
->limit(18, null)
->select('user_listings.*,image.*,user_states.*')
->select('COUNT(user_bookings.book_listing) as totalBooked')
->from('user_listings')
->join('user_bookings', 'user_bookings.book_listing = user_listings.list_reference', 'left')
->join('(SELECT * FROM user_images WHERE user_images.img_key IN(SELECT MIN(user_images.img_key) FROM user_images GROUP BY user_images.img_listing)) AS image',
'image.img_listing = user_listings.list_reference')
->join('user_states', 'user_states.state_id = user_listings.list_state')
->group_by('user_listings.list_reference')
->get();
Basically, I had to do a select from the join table for user_images. Hope it helps someone else :)

Allowing user input once per minute

I have trouble getting this to work.
The thing is that a user is only allowed to create a comment once per minute. As simple as that....
$checkLastComment = Comment::where('user_id', '=', 1)
->where('created_at', '<', 'CURDATE() + INTERVAL 1 MINUTE')->count();
You should use here rather:
$checkLastComment = Comment::where('user_id', '=', $id)
->where('created_at', '>=', 'DATE_SUB(NOW(), INTERVAL 1 MINUTE)')->first();
if ($checkLastComment) {
// user not allowed to add new comment
}
3 issues in your code:
You need greater than >, not less than < operator
You need raw condition
You can't use curdate() since it's time part is 00:00:00 always.
So here's what you want:
$notAllowedToComment = Comment::where('user_id', '=', 1)
->where('created_at', '>', DB::raw('now() - INTERVAL 1 MINUTE'))->count();

How to create a select where count is not zero in MySQL

Here's what I'm trying to do. I'm trying to select from a forum views table all of the user_ids where there are 5 or more records. That's fairly easy (this is Zend):
$objCountSelect = $db->select()
->from(array('v' =>'tbl_forum_views'), 'COUNT(*) AS count')
->where('u.id = v.user_id')
->having('COUNT(user_id) >= ?', 5)
;
But I need to somehow connect this to my users table. I don't want to return a result if the count is greater than 5. I tried this:
$objSelect = $db->select()
->from(array('u' => 'tbl_users'), array(
'id as u_id',
'count' => new Zend_Db_Expr('(' . $objCountSelect . ')'),
))
;
But that returns a record for every user, leaving blank the count if it's less than or equal to 5. How do I exclude the rows where the count is less than or equal to 5?
I figured it out, but wanted to post the answer in case someone else had the same issue. I added:
->having('count > 0')
to the second select and now it works.