How to allow duplicate mysql row id in array? - php

My data in table t1 as below (only 2 record),
+-----------+-----------------+----------+
| shid | lvlmin | lvlmax |
+-----------+-----------------+----------+
| 1 | 1 | 10 |
| 2 | 5 | 10 |
+----------------------------------------+
My php code is:
$userinfo[0] = '9';
$ghunt = DB::fetch_all("SELECT shid FROM t1
WHERE lvlmin <= ".$userinfo[0]." AND lvlmax >= ".$userinfo[0].
"ORDER BY rand() LIMIT 5");
print_r($ghunt);
Result got 2 array:
Array ( [0] => Array ( [shid] => 2 ) [1] => Array ( [shid] => 1 ) )
How do I do when the array result is less than the LIMIT 5 in mysql query, auto use the array result in $ghunt to fill up the array?
What I mean is:
Array (
[0] => Array ( [shid] => 2 )
[1] => Array ( [shid] => 1 )
[2] => Array ( [shid] => 2 )
[3] => Array ( [shid] => 1 )
[4] => Array ( [shid] => 1 )
)
The shid can be random place in array.

Why don't you do something like this?
If (count($ghunt) < 5){
$realResultCount = count($ghunt);
for ($i = realResultCount; $i <= 5; $i++){
$ghunt[$i] = $ghunt[rand(0,realResultCount-1)];
}
}
Basically, what above code does is, if ghunt has less than 5 records in it, it tops it up to 5, by randomly selecting records out of initially returned records.

I don't code PHP, but I can describe one way you can achieve your goal simply. Most languages have a MOD operator, usually % - the php manual page for mod is here
It gives us the remainder of a division operation, so 10 mod 3 is 1, because 10 divided by 3 is 9 remainder 1
A useful property of MOD then, is that it always cycles between 0 and 1 less than what you're modding by. If you mod an incrementing number by 5, the result will always be 0,1,2,3,4,0,1,2,3,4 in a cycle. This means you can have a for loop with some incrementing number, mod by an array length and the result will be an integer that is certainly an array index. If the loop variable goes higher than the end of the array, the mod operator will make it wrap round to the start of the array again
MyArray[ 1746262848 mod MyArray.length ]
Will certainly not crash, even if the array only has 2 items
So for your case, just have a loop.. make he following pseudo code into PHP
// run the loop 5 times
For I as integer = 0 to 4 do
Print MyArray[ i mod MyArray.length ]
If you have 2 items in your array, A and B, it will simply print ABABA
If you have 3 items A B C it will print ABCAB
Hopefully this info will be helpful to you for implementing a solution in php for this, and many future problems. Mod can be really useful for implementing various things when working with arrays

Related

php mysql check if vendor has 3 low consecutive ratings

on my ratings table for my software i have 4 fields.
id autoincrement
rvid vendor id
ratedate date of rating
rating the actual numeric rating
I have done alot with it over the last few months but this time im stumped and i cant get a clear picture in my head of the best way to do this. What i am trying to do is find out if the vendor has had 3 low 'consecutive' ratings. If their last three ratings have been < 3 then i want to flag them.
I have been playing with this for a few hours now so i thought i would ask (not for the answer) but for some path direction just to push me forward, im stuck in thought going in circles here.
I have tried GROUP BY and several ORDER BY but those attempts did not go well and so i am wondering if this is not a mysql answer but a php answer. In other words maybe i just need to take what i have so far and just move to the php side of things via usort and the like and do it that way.
Here is what i have so far i did select id as well at first thinking that was the best way to get the last consective but then i had a small breakthrough that if they have had 3 in a row the id does not matter, so i took it out of the query.
$sql = "SELECT `rvid`, `rating` FROM `vendor_ratings_archive` WHERE `rating` <= '3' ORDER BY `rvid` DESC";
which give me this
Array
(
[0] => Array
(
[rvid] => 7
[rating] => 2
)
[1] => Array
(
[rvid] => 5
[rating] => 1
)
[2] => Array
(
[rvid] => 5
[rating] => 0
)
[3] => Array
(
[rvid] => 5
[rating] => 3
)
)
this is just just samples i tossed in the fields, and there are only 4 rows here where as in live it will be tons of rows. But basically this tells me that these are the vendors that have low ratings in the table. And that is where i get stumpted. I can only do one sort in the query so that is why i am thinking that i need to take this and move to the php side to finish it off.
I think i need to sort the elements by rvid with php first i think, and then see if three elements in a row are the same vender (rvid).
Hope that makes sense. My brain hurts lol...
update - here is all of the table data using *
Array
(
[0] => Array
(
[id] => 7
[rvid] => 7
[ratedate] => 2016-05-01
[rating] => 2
)
[1] => Array
(
[id] => 8
[rvid] => 5
[ratedate] => 2016-05-01
[rating] => 1
)
[2] => Array
(
[id] => 6
[rvid] => 5
[ratedate] => 2016-05-01
[rating] => 0
)
[3] => Array
(
[id] => 5
[rvid] => 5
[ratedate] => 2016-05-01
[rating] => 3
)
)
Here's one way you can begin approaching this - completely in SQL:
Get the last rating for the vendor. ORDER BY date DESC, limit 1.
Get the second to last rating for the vendor. ORDER BY date DESC, limit 1, OFFSET 1.
Then write a query that does a LEFT join of the first two tables. You will have a dataset that has three columns:
vendor id
last rating
second to last rating
Then you can write an expression that says "if column1 is <3 and column2 < 3, then this new column is true"
You should be able to extend this to three columns relatively easily.
Here is what a came up with to solve this riddle. I think explaining it on here helped as well as Alex also helped as he keyed my brain on using the date. I first started looking at using if statment inside of the query and actually that got my brain out of the box and then it hit me what to do.
It is not perfect and certainly could use some trimming to reduce the code, but i understand it and it seems to work, so that is par for me on this course.
the query...
$sql = "SELECT `rvid`, `ratedate`,`rating` FROM `vendor_ratings_archive` WHERE `rating` <= '3' ORDER BY `ratedate`, `rvid` DESC";
which gives me this
Array
(
[0] => Array
(
[rvid] => 7
[ratedate] => 2016-05-01
[rating] => 2
)
[1] => Array
(
[rvid] => 5
[ratedate] => 2016-05-01
[rating] => 1
)
[2] => Array
(
[rvid] => 5
[ratedate] => 2016-05-01
[rating] => 0
)
[3] => Array
(
[rvid] => 5
[ratedate] => 2016-05-01
[rating] => 3
)
)
notice how vendor (rvid) 5 is grouped together which is an added plus.
next a simple foreach to load a new array
foreach($results as $yield)
{
$rvidarray[] = $yield['rvid'];
}//close foreach
which gives me this
Array
(
[0] => 7
[1] => 5
[2] => 5
[3] => 5
)
then we count the array values to group dups
$rvidcounter = array_count_values($rvidarray);
which results in this
Array(
[7] => 1
[5] => 3
)
so now vender 7 as 1 low score and vendor 5 has 3 low scores and since they were already sorted by date i know that its consecutive. Well it sounds good anyway lol ")
then we create our final array with another foreach
foreach($rvidcounter as $key => $value)
{
//anything 3 or over is your watchlist
if($value > 2)
{
$watchlist[] = $key; //rvid number stored
}
}//close foreach
which gives me this
Array
(
[0] => 5
)
this was all done in a service function. So the final deal is everyone in this array has over 3 consecutive low ratings and then i just use a returned array back in my normal php process file and grab the name of each vender by id and pass that to the html and print out the list.
done...
please feel free to improve on this if you like. I may or may not use it because the above code makes sense to me. Something more complicated may not make sense to me 6 mos from now lol But it would be interesting to see what someone comes up with to shorten the process a bit.
Thanks so much and Happy Coding !!!!!
Dave :)
You could do it in SQL like that:
SET #rvid = -1;
SELECT DISTINCT rvid FROM
(
SELECT
rvid,
#neg := rating<3, /* 0 or 1 for addition in next line */
#count := IF(#rvid <> rvid , #neg, #count+#neg) AS `count`, /* set or add */
#rvid := rvid /* remember last row */
FROM
testdb.venrate
ORDER BY
rvid, datetime desc
) subq
WHERE count>=3
;
You set a variable to a non existing id. In each chronologically sorted row you check if rating is too low, that results in 1 (too low) or 0 (ok). If rvid is not equal to the last rvid, it means a new vender section is beginning. On begin of section set the value 0 or 1, else add this value. Finally store the current row's rvid for comparison in next row process.
The code above is looking for 3 consecutive low ratings (low means a value less than 3) over all the time.
A small modification checks if all the latest 3 ratings has been equal to or less than 3:
SET #rvid = -1;
SELECT DISTINCT
rvid
FROM
(
SELECT
rvid,
#high_found := rating>3 OR (#rvid = rvid AND #high_found) unflag,
#count := IF(#rvid <> rvid , 1, #count+1) AS `count`,
#rvid := rvid /* remember last row */
FROM
testdb.venrate
ORDER BY
rvid, datetime desc
) subq
WHERE count=3 AND NOT unflag
;

Instead of php while loop and multiple connections to mysql want to connect only once

Example of mysql is here http://sqlfiddle.com/#!9/68653/2
Mysql table (named topics)
TopicId | TopicName | ClosestUpperLevelId
--------------------------------------------
1 | Books | 0
2 | BooksAboutCss | 1
3 | BooksAboutHtml | 1
4 | BooksAboutCss1 | 2
5 | BooksAboutCss2 | 2
6 | BooksAboutHtml1 | 3
7 | BooksAboutHtml2 | 3
8 | E-Books | 0
9 | Magazines | 0
For top level topics ClosestUpperLevelId is 0. For subtopics ClosestUpperLevelId is TopicId of closest upper level topic
(TopicId - ClosestUpperLevelId)
Books (1-0)
BooksAboutCss (2-1)
BooksAboutCss1 (4-2)
BooksAboutCss2 (5-2)
BooksAboutHtml (3-1)
BooksAboutHtml1 (6-3)
BooksAboutHtml2 (7-3)
E-Books (8-0)
Magazines (9-0)
For example, i have created one page and location of the page is domain.com/Books/BooksAboutCss/BooksAboutCss2
Now i decided to edit the page. For example i want to edit location (topic or category) of the page and set it to domain.com/Magazines. So i need to fetch all topics, related with existing (saved) page. Then will create select boxes for each group (level) of topics.
At the moment tried to use php while and multiple times to connect to mysql and get data. Like below code. How can i get the same result without php while? How connect to mysql only once and fetch all necessary data? Do i need to use mysql while https://dev.mysql.com/doc/refman/5.1/en/while.html?
$topic_names_1[0]['UpperLevelNumberRenamed'] = 5;//just set some value to start to fetch
while ( trim($topic_names_1[0]['ClosestUpperLevelId']) != 0 ){
try {
$stmt_1 = $db->prepare('
SELECT `TopicId`, `TopicName`, `ClosestUpperLevelId`
FROM `topics`
WHERE `ClosestUpperLevelId` =
(
SELECT `ClosestUpperLevelId`
FROM `topics`
WHERE `TopicId` = ?
)
;');
$stmt_1->execute( array( trim($topic_names_1[0]['UpperLevelNumberRenamed']) ) );
$topic_names_1 = $stmt_1->fetchAll(PDO::FETCH_ASSOC);
echo '<pre>', print_r($topic_names_1), ' topic_names_1 __</pre>';
}//try {
catch (PDOException $e){
echo "<br> stmt_1 DataBase Error: " .htmlspecialchars( $e->getMessage() , ENT_QUOTES, "UTF-8").'<br>';
}
catch (Exception $e) {
echo " stmt_1 General Error: ".htmlspecialchars( $e->getMessage() ).'<br>';
}
}//while ( trim($topic_names[0]['UpperLevelNumberRenamed']) != 0 )
As result get arrays like this
Array
(
[0] => Array
(
[TopicId] => 4
[TopicName] => BooksAboutCss1
[ClosestUpperLevelId] => 2
)
[1] => Array
(
[TopicId] => 5
[TopicName] => BooksAboutCss2
[ClosestUpperLevelId] => 2
)
)
1 topic_names_1 __
Array
(
[0] => Array
(
[TopicId] => 2
[TopicName] => BooksAboutCss
[ClosestUpperLevelId] => 1
)
[1] => Array
(
[TopicId] => 3
[TopicName] => BooksAboutHtml
[ClosestUpperLevelId] => 1
)
)
1 topic_names_1 __
Array
(
[0] => Array
(
[TopicId] => 1
[TopicName] => Books
[ClosestUpperLevelId] => 0
)
[1] => Array
(
[TopicId] => 8
[TopicName] => E-Books
[ClosestUpperLevelId] => 0
)
[2] => Array
(
[TopicId] => 9
[TopicName] => Magazines
[ClosestUpperLevelId] => 0
)
)
1 topic_names_1 __
Update
Found one example with mysql while. Trying to create own code
Created this
SET `ClosestUpperLevelId` := 2;
WHILE `ClosestUpperLevelId` > 0
DO
SELECT `TopicId`, `TopicName`, `ClosestUpperLevelId`;
END WHILE;
and this (http://sqlfiddle.com/#!9/68653/7)
CREATE PROCEDURE dowhile()
BEGIN
DECLARE `ClosestUpperLevelId` INT DEFAULT 2;
WHILE `ClosestUpperLevelId` > 0 DO
SELECT `TopicId`, `TopicName`, `ClosestUpperLevelId`;
END WHILE;
END;
Got error...
You could just move your select statement before the while loop and take out the topic_id from the where clause. Then in your loop retrieve from the complete record set using an array search function or similar. By running same query once your dB will be able to cache results
Relational databases like MySQL aren't naturally good at storing hierarchical data, but there are ways of doing it. The two ways I know of are "adjacency lists" and "nested sets".
For an adjacency list, you'd simply store a "parent_id" field for each row. Root rows (that have no parent) can just have NULL for their parent_id field. Adjacency lists are easy to manage, but not very flexible and require recursive queries to find a path from root to leaf (unless you're only going 2 levels deep, then you can simply JOIN).
Here's an example:
id | parent_id | name
0 NULL grandfather
1 0 father
2 1 grandson
3 1 granddaughter
This query would help assemble the data:
SELECT * FROM
`people` AS p1
JOIN `people` p2
ON p1.id = p2.parent_id
Any more than those two levels and you need recursion. Alternatively, you could just query the entire table and assemble it in code.
Nested sets are a little more complicated, but allow you to easily query all the way up the tree for a given leaf node. It's much easier to understand nested sets at first by seeing a visual, check this out:
https://en.wikipedia.org/wiki/Nested_set_model
And here's what your schema would look like:
left | right | name
0 7 grandfather
1 6 father
2 3 grandson
4 5 granddaughter
And here's an example to fetch father and children:
SELECT *
FROM `people`
WHERE `left` >= 1 AND `right` <= 6
Nested sets have the downside that the entire table's left and right values need to be updated when the hierarchy changes.
Google "managing hierarchical data in mysql" for more information. I hope this helps.

mysql get result of most frequent value of every post

I found some similar questions with good answers but i couldnt figure out how to apply this to my specific case. I have a site where users can rate there favorite post from 1-6. Every number is a different category.
Now i need to know the most frequently votes for every single post. So i need to count every post id and than the most frequent values of every post id.
After that i wanna update every result in another table. (dont know how to figure this out right now i'm not that good with Mysql yet).
this are the two columns where i need to know how often every post exist in post_id and what is the most frequently voting number of every single post.
just an example of my table (value = voting)
value | post_id
---------------
3 | 12
1 | 6
4 | 13
2 | 5
6 | 12
5 | 6
i need the output like this to know which post is mostly votet for which category.
post | most voted in this category
---------------
1 | 3
2 | 5
3 | 6
4 | 1
5 | 4
6 | 6
i need this for every post in the table. and than i would need to update every post in another table. i guess i have to do this in a loop.
but im already stuck at the first part.
all i have is this. for the first part.
<?php global $wpdb;
$test = $wpdb->get_results('SELECT posts_id, value, COUNT(posts_id) AS ActionCount
FROM rating_item_entry_value
GROUP BY posts_id
ORDER BY ActionCount DESC');
echo '<pre>';
print_r($test);
echo '</pre>';
and this is the output i get
Array
(
[0] => stdClass Object
(
[posts_id] => 0
[value] => 5
[ActionCount] => 7
)
[1] => stdClass Object
(
[posts_id] => 221
[value] => 3
[ActionCount] => 3
)
[2] => stdClass Object
(
[posts_id] => 197
[value] => 5
[ActionCount] => 2
)
[3] => stdClass Object
(
[posts_id] => 164
[value] => 3
[ActionCount] => 1
)
)
for the example.
I have no idea how to do this better, trying a lot but can't figure it out. does anyone has a good solution how to get the most frequent number for every single id? (and maybe how to safe the results in a variable to update every post in another table within a loop?) thank u so much for any help. regards
most frequently means count aggregation and group by frequency. you can map this to your problem:
select
x.amount,
count(*) as times -- I forgot that row
from
X x
group by
x.amount
order by
count(*) DESC
// edit to you mean that
select
post_id,
value,
count(*)
from
your_table
group by
post_id,
value
order by
count(*) desc

Add extra cost per array base on key value per producto

everyone, I have the following problem I need to solve...
I'm building a shopping cart, everything was working fine until I decide to add some extras, so when you buy a product it let you add some extra items for an extra cost, so let say
Shoes $20.00 if you want to add an extra "coluor" it will cost you $10 extra...
so if you have only 1 item(one pair of shoes) it works fine, the problem is when you add an extra pair of shoes for a total of 2 items in your cart
Sport Shoes $20 + 10 per colour
Formal Shoes $30
so with that we can see that the total to be paid is only $60.00, but it shows $70.00 so why is that? what I have seen is that the next product get the extra cost from the first item, and if the next item has an extra, it get added plus the extras from the first extras of the first product... as you can see is kind of confusing.. so here is my code.
First, you need to understand how my array is build so here it is:
Normal Array for a single item:
Array
(
[cart] => Array
(
[2] => Array
(
[10] => Array
(
[quantity] => 1
[extra1] =>
[extra2] =>
)
)
)
)
So my session is that, the first ID[2] is the products ID, the second[10] is the Stock ID, the quantity and the extras... that works just fine... the problem is with the second.
Array
(
[cart] => Array
(
[2] => Array
(
[10] => Array
(
[quantity] => 1
[extra1] => Green +$10
[extra2] => Red +$10
)
)
[1] => Array
(
[7] => Array
(
[quantity] => 1
[extra1] => 0
[extra2] => 0
)
)
)
)
so that's what the session looks like, I'm able to manipulate that array in any way I need, such as, update quantity, add extras, unset product or stock and so on... also the prices with discounts are display and sum or subtracted correctly the problem are the extras... which I don't understand why I have such a hard time to manipulate...
the code that I'm using to display the information is as follow:
$s_pq = $_SESSION['cart'];
$ext1 = 0;
$ext2 = 0;
foreach ($s_pq as $kes => $values){
$qidq = $_SESSION['cart'][$kes];
foreach ($qidq as $sks => $svs ){
$ex_ex1 = $svs['extra1'];
$ex_ex2 = $svs['extra2'];
if ($ex_ex1 != '' && $ex_ex1 > 0 ) {
$extt1 += 10;
} else {$extt1 = 0;}
if ($ex_ex2 != '' && $ex_ex2 > 0 ) {
$extt2 += 10;
} else {$extt2 = 0;}
}
}
That little code is the same structure that I use to display the rest of the information:
$s_pq = $_SESSION['cart'];
foreach ($s_pq as $kes => $values){
// display product name and extra data related to that product ID
// DB Query to extract the info a few if's and echos..
$qidq = $_SESSION['cart'][$kes];
foreach ($qidq as $sks => $svs ){
// Another few DB queries to fetch information for the stock for each item
}
}
is a very simple code to work with the array from my session and is working fine, but the problem remains... so in the first code the idea is to see if the key [extra1] or [extra2] are different from " " if so it means that it has information other than " " which can be a single character but not empty and not space or zero's, if that is the case then add extra $10 if not then 0...
in another statement I use those variables $extt2 and $extt1 to add the values to the final cost
$final = round($db_price, 2) * $num_items_total + $extt1 + $extt2;
echo '$ '.$final;
with that code I display the total cost for each item in the cart.
so that is all I have for the cart session it will have nothing else but that...
last but not least here is an array for multiple size with some extras...
Array
(
[cart] => Array
(
[2] => Array
(
[10] => Array
(
[quantity] => 1
[extra1] => asdasd
[extra2] => asdasd
)
[12] => Array
(
[quantity] => 1
[extra1] =>
[extra2] =>
)
)
[1] => Array
(
[7] => Array
(
[quantity] => 1
[extra1] => as
[extra2] => asda
)
)
)
)
This is telling you that:
Name | Descr | Total
| Size 10 |
Item [2] | quantity 1 |
$20 | Extra 1 +10 | $60.00 <-- Good total
| Extra 2 +10 |
|--------------------|
| Size 12 |
| quantity 1 |
-----------------------------------------
Item [1] | quantity 1 |
$20 | Extra 1 +10 | $60.00 <-- Wrong total
| Extra 2 +10 | it should be $40.00
-----------------------------------------
Total $120.00
Thank you for taking the time, I appreciate any help you can provide!
F I X E D
I went through all my files line by line, and what i have discover was shocking! how could be so stupid!!! what happen was that I have 4 loops [loop [loop vars [loop [loop]]]] and that was the problem with the extras, the first 2 loops already show the information I need, I didn't see them because the file is damm long and I forgot about them, and the second loops I though I was outside the first 2 loops but I wasn't! and that was the problem, so I had to remove the other 2 loops and work with the first 2 loops and is working flawlessly; !! omg, 2 day!!, two day with that!! Thank you all!
So in other words, you can not use loops inside loops for the same purpose, basically was I was creating was a flood inside a loop, and for that in my case my variables never got the change to reset and that was because, the first loop was pulling the information when it was done it jump to the next key, but the loop inside was never finish so my vars never reset and that was the problem...
Again, thank you all.
Hmm its always the little things that kills code so I'll start there. I noticed that $extt1 and $extt2 are never reset in the foreach loop. This may be the source of the incrementing extra cost error. They are initialized before that loop but never reset between items.
Are you setting a default value for '$extt1' & '$extt2'? I see that you are setting:
$ext1 = 0;
$ext2 = 0;
But then you are setting:
$extt1 += 10;
And then you are totaling up all of the '$extt1' variables, but not resetting them for each loop.
So, the first time that you use it, it should be set to zero and then if it matches conditions, it will modify it. The next time you use it, since you're not setting it to zero first, '$extt1' still equals 10.
Move
$ext1 = 0;
$ext2 = 0;
inside your foreach loop
$s_pq = $_SESSION['cart'];
foreach ($s_pq as $kes => $values){
$ext1 = 0;
$ext2 = 0;
$qidq = $_SESSION['cart'][$kes];
foreach ($qidq as $sks => $svs ){
$ex_ex1 = $svs['extra1'];
$ex_ex2 = $svs['extra2'];
if ($ex_ex1 != '' && $ex_ex1 > 0 ) {
$extt1 += 10;
} else {$extt1 = 0;}
if ($ex_ex2 != '' && $ex_ex2 > 0 ) {
$extt2 += 10;
} else {$extt2 = 0;}
}
}

PHP: count how many times a number appears in an array?

I'm running a loop basically that will make an array that contains a million numbers between 1 and 10, how do I iterate through it and count how many of each there are?
Like:
1 - 201491 times
2 - 23091 times
There's a native PHP function for that:
$count = array_count_values($array);
print_r($count);
will output:
Array
(
[1] => 2
[hello] => 2
[world] => 1
)

Categories