I have a table that contains an unknown number of elements. These represent business sectors.
Array ([0] => 1 [1] => 3 [2] => 6 [3] => 7)
In this case this activity is linked to topics 1, 3, 6 and 7.
I Have some members who have indicated their fields of interest when they register. Interest fields correspond to sectors of activities.
When a new activity is announced, I would like to send an email to members who have checked at least one common interest with the activity. But I have no idea how to retrieve the email of all those members().
In the database the interests of members is stored like this: 246
The first member would be interested in sectors 2, 4 and 6.
I know how to do if there is only one business sector for the activity (example if value = 1).
function readMemberInterest($value) {
$datas = $this->db->select("email")
->from($this->table)
->like('interet',$value,'both');
return $datas;
}
But I do not know where and how to place my LOOP and my OR (is for example value = Array ([0] => 1 1 => 3 [2] => 6 [3] => 7) ).
Briefly, I want to retrieve email members who have at least one common interest with activity. Any tips?
I hope to be clear, my English is not so great ...
Thanks
Related
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
;
I have a list of courses and the hours they require for students to take them. The courses are as follows:
CON8101 Residential Building/Estimating 16 hrs/w
CON8411 Construction Materials I 4 hrs/w
CON8430 Computers and You 4 hrs/w
MAT8050 Geometry and Trigonometry 4 hrs/w
I have used this RegEx to extract the name of course and the hours each course takes each week. There are more than 4 courses, the 4 are examples above. There can be as many as 50 courses.
$courseHoursRegEx = "/\s[0-9]{1,2}\shrs/w/";
$courseNameRegEx = "/[a-zA-Z]{3}[0-9]{4}[A-Z]{0,1}\s?/[a-zA-Z]{3,40}/";
And applied the following function (not sure if 100% right) to extract the RegEx'd strings. Using $courseLine is the variable I saved the string of each line from a text document that early I have fopened. It keeps track of the total hours that has been extracted from the string.
$courses is an array of check boxes that the user enters in the html section
$totalHours += GetCourseHours($courseLine);
function GetCourseHours($couseLine)
{
if(!preg_match($courseHoursRegEx, $courseLine))
{
return $courseLine;
}
}
function GetCourseName($courseLine)
{
if(!preg_match($courseNameRegEx, $courseLine))
{
return $courseLine;
}
}
I used a foreach loop to output all the selected courses to be sorted out in a table.
foreach($courses as $course)
{
$theCourse = GetCourseName($course);
$theHours = GetCourseHours($course)
}
Edit: output code
for($i = 1; $i <= $courses; ++$i)
{
printf("<tr><td>\$%.2f</td><td>\$%.2f</td></tr>", $theCourse, $theHours);
}
I am not sure how to output what I have into a dynamic table organized by the course name, and hours for each course. I cannot get my page to run, I cannot find any syntax errors, I was afraid it was my logic.
First of all, (after fixing a few minor things within the regexes) you can do all of that in one preg_ call. Here is how:
preg_match_all("~([a-zA-Z]{3}\d{4}[A-Z]{0,1}\s.+)\s(\d{1,2})\shrs/w~", $str, $matches);
$str can either be a multiline string with all rows at once. Or you can pass in a single line at a time. If you pass in all lines at once, $matches will afterward look like this:
Array
(
[0] => Array
(
[0] => CON8101 Residential Building/Estimating 16 hrs/w
[1] => CON8411 Construction Materials I 4 hrs/w
[2] => CON8430 Computers and You 4 hrs/w
[3] => MAT8050 Geometry and Trigonometry 4 hrs/w
)
[1] => Array
(
[0] => CON8101 Residential Building/Estimating
[1] => CON8411 Construction Materials I
[2] => CON8430 Computers and You
[3] => MAT8050 Geometry and Trigonometry
)
[2] => Array
(
[0] => 16
[1] => 4
[2] => 4
[3] => 4
)
)
Now you can simply iterate over all names in $matches[1] and sum up the hours in $matches[2]. Notice that those two inner arrays correspond to what's inside of the round brackets I used in the regex. These are so called subpatterns, and they capture additional (sub-)matches. Also $matches[0] will always contain the full match of the whole pattern, but you don't need that in this case.
I'm hoping somebody can clear up this issue I am having. None of the other answers on SO seemed to help me out for some reason.
I have 2 tables with a HABTM relationship. Publications have many authors, and authors have many publications. In my case, I am attempting to output a list of all of the publications in the database, along with their corresponding authors.
I have the following tables:
publications:
id title
0 TestPublication
authors:
id firstname lastname middle
0 John Doe A
authors_publications:
id author_id publication_id
0 0 0
The 'id' column of each table is set as the primary key.
My Publication model looks like:
class Publication extends AppModel {
var $name = 'Publication';
var $hasAndBelongsToMany = array(
'Author'=>array(
'className'=>'Author'
)
);
}
And finally, the PublicationsController has the following function:
function index() {
$publications = $this->Publication->find('all');
$this->set('publications', $publications);
}
Here is what publications now contains:
Array ( [0] => Array ( [Publication] => Array ( [id] => 0 [title] => TestPublica [type_id] => 1 ) [Author] => Array ( ) ) )
Why is this? I am expecting (perhaps that is my problem...) that the author John Doe should be present in the Author array. If it should be, where am I going wrong? Do I need a bindModel call somewhere in there?
Or...is the code actually executing the way it should and my expectations are incorrect? If so, how would I return a list of all of the publications along with all of their authors?
Thanks for your time!
I believe I found the problem. I was manually inserting records into the DB for testing purposes. I set the primary key id's on the first record of each table to zero. SQL DBs typically (or always?) start the first record with a primary key index of 1, not 0. I'm not sure WHY cake did not work with this, but changing the id's to 1 solved the problem. Weird...
Let's say I have two tables, people and families.
families has two fields - id and name. The name field contains the family surname.
people has three fields - id, family_id and name - The family_id is the id of the family that that person belongs to. The name field is that person's first name.
It's basically a one to many relationship with one family having many people.
I want to get a lists of name sets, ordered by the highest occurrence of the largest set of names across families.
That probably doesn't make much sense...
To explain what I want further, we can score each set of names. The 'score' is the array size * number of occurrences across families.
For example, let's say two names, 'John' and 'Jane' both existed in three families - That set's 'score' would be 2*3 = 6.
How could I get an array of sets of names, and the set's 'score', ordered by each set's score?
Sample Result Set (I've put it in a table layout, but this could be a multi-dimensional array in PHP) - Note this is just randomly thought up and doesn't reflect any statistical name data.
names | occurrences | score
Ben, Lucy | 4 | 8
Jane, John | 3 | 6
James, Rosie, Jack | 2 | 6
Charlie, Jane | 2 | 4
Just to clarify, I'm not interested in sets where:
The number of occurrences is 1 (obviously, just one family).
The set size is 1 (just a common name).
I hope I have explained my somewhat complex problem - if anyone needs clarification please say.
OK, got it:
<?php
require_once('query.lib.php');
$db=new database(DB_TYPE,DB_HOST,DB_USER,DB_PASS,DB_MISC);
$qry=new query('set names utf8',$db);
//Base query, this filters out names that are in just one family
$sql='select name, cast(group_concat(family order by family) as char) as famlist, count(*) as num from people group by name having num>0 order by num desc';
$qry=new query($sql,$db);
//$qry->result is something like
/*
Array
(
[name] => Array
(
[0] => cathy
[1] => george
[2] => jack
[3] => john
[4] => jane
[5] => winston
[6] => peter
)
[famlist] => Array
(
[0] => 2,4,5,6,8
[1] => 2,3,4,5,8
[2] => 1,3,5,7,8
[3] => 1,2,3,6,7
[4] => 2,4,7,8
[5] => 1,2,6,8
[6] => 1,3,6
)
[num] => Array
(
[0] => 5
[1] => 5
[2] => 5
[3] => 5
[4] => 4
[5] => 4
[6] => 3
)
)
$qry->rows=7
*/
//Initialize
$names=$qry->result['name'];
$rows=$qry->rows;
$lists=array();
for ($i=0;$i<$rows;$i++) $lists[$i]=explode(',',$qry->result['famlist'][$i]);
//Walk the list and populate pairs - this filters out pairs, that are specific to only one family
$tuples=array();
for ($i=0;$i<$rows;$i++) {
for ($j=$i+1;$j<$rows;$j++) {
$isec=array_intersect($lists[$i],$lists[$j]);
if (sizeof($isec)>1) {
//Every tuple consists of the name-list, the family list, the length and the latest used name
$tuples[]=array($names[$i].'/'.$names[$j],$isec,2,$j);
}
}
}
//Now walk the tuples again rolling forward, until there is nothing left to do
//We do not use a for loop just for style
$i=0;
while ($i<sizeof($tuples)) {
$tuple=$tuples[$i];
//Try to combine this tuple with all later names
for ($j=$tuple[3]+1;$j<$rows;$j++) {
$isec=array_intersect($tuple[1],$lists[$j]);
if (sizeof($isec)>0) $tuples[]=array($tuple[0].'/'.$names[$j],$isec,$tuple[2]+1,$j);
}
$i++;
}
//We have all the tuples, now we just need to extract the info and prepare to sort - some dirty trick here!
$final=array();
while (sizeof($tuples)>0) {
$tuple=array_pop($tuples);
//name list is in $tuple[0]
$list=$tuple[0];
//count is sizeof($tuple[1])
$count=sizeof($tuple[1]);
//length is in $tuple[2]
$final[]=$tuple[2]*$count."\t$count\t$list";
}
//Sorting and output is all that is left
rsort($final);
print_r($final);
?>
I am sorry I just realized I use a query lib that I can't source in here, but from the comment you will easily be able to create the arrays as in the section "Initialize".
Basically what I do is starting with the pairs I keep an array of the families all the names in the current name list belong to, then intersect it with all not-yet tried names.
Will this work?
SELECT
f.name AS 'surname',
GROUP_CONCAT(DISTINCT p.name ORDER BY p.name) AS 'names',
COUNT(DISTINCT p.name) AS 'distinct_names',
COUNT(p.id) AS 'occurrences',
COUNT(DISTINCT p.name) * COUNT(p.id) AS 'score'
FROM
families f
LEFT JOIN people p ON ( f.id = p.family_id )
GROUP BY
f.id
ORDER BY
f.name
After getting negative feedback from asking this question in a new question... here is my revised question. Yes it is the same project I am working on, but I was unclear that I needed to basically have a Round Robin type of scheduler.
I'm working on a Round Robin Style Hockey League Scheduler, and need some help.
The overall goal is for the end admin user to be able to punch in 3 variables and have it perform a round Robin style schedule until the WEEKS counter has been hit. Below is an example of the amount of teams and the amount of weeks games are played.
$Teams = array('team1','team2','team3','team4','team5','team6','team7','team8');
$Weeks = 16;
The goal is to have it loop 16 times, making 4 games a week, having each team playing 1 time a week. The round robin algorithm should have teams playing different teams each week until all possibles combinations have been made, but not exceeding 16 weeks. In the event that we only have 4 teams or less teams than possible combinations, we would need to have the round robin start over again until the weeks number was hit.
EDIT:
I am about 90% into what I needed this script to do... but I am stuck on one thing. I need help with merging a multi-dimensional array.
First are the Tiers. Next are the Weeks (all are week 1). Then are the Games for the team match up.
Array
(
[1] => Array
(
[1] => Array
(
[1] => Array
(
[home] => Whalers
[visitor] => Lumberjacks
)
[2] => Array
(
[home] => Team America
[visitor] => Wolfpack
)
)
)
[2] => Array
(
[1] => Array
(
[1] => Array
(
[home] => Warriors
[visitor] => Litchfield Builders
)
[2] => Array
(
[home] => Icemen
[visitor] => Nighthawks
)
)
)
[3] => Array
(
[1] => Array
(
[1] => Array
(
[home] => The Freeze
[visitor] => Devils Rejects
)
[2] => Array
(
[home] => Cobras
[visitor] => New Haven Raiders
)
[3] => Array
(
[home] => Crusaders
[visitor] => Whalers
)
[4] => Array
(
[home] => Blizzard
[visitor] => CT Redlines
)
)
)
)
I want the end result to drop the tier and merge all same weeks games together to look like the following:
Array
(
[1] => Array
(
[1] => Array
(
[home] => Whalers
[visitor] => Lumberjacks
)
[2] => Array
(
[home] => Team America
[visitor] => Wolfpack
)
[3] => Array
(
[home] => Warriors
[visitor] => Litchfield Builders
)
[4] => Array
(
[home] => Icemen
[visitor] => Nighthawks
)
[5] => Array
(
[home] => The Freeze
[visitor] => Devils Rejects
)
[6] => Array
(
[home] => Cobras
[visitor] => New Haven Raiders
)
[6] => Array
(
[home] => Crusaders
[visitor] => Whalers
)
[8] => Array
(
[home] => Blizzard
[visitor] => CT Redlines
)
)
)
Maybe something like this?
<?php
$teams = array(
'Team 1',
'Team 2',
'Team 3',
'Team 4',
'Team 5',
'Team 6',
'Team 7',
'Team 8'
);
function getMatches($teams) {
shuffle($teams);
return call_user_func_array('array_combine', array_chunk($teams, sizeof($teams) / 2));
}
for ($i = 0; $i < 14; $i += 1) {
print_r(getMatches($teams));
}
I didn't really get how you define the schedule, so if you can explain this a bit, I'll try to help.
Pop one off, randomize, pop another. There's your game. If one is left over, some random team has to be a workhorse and play two games this week:
for ($week=1; $i<=$totalWeeksPlayed; $i++)
{
$games = 0;
$temp = $teams;
while (count($temp) > 1)
{
$team = array_shift($temp);
shuffle($temp);
$opponent = array_shift($temp);
$game[$week][$games] = $team . ' vs' . $opponent;
$games++;
}
if (count($temp) == 1)
{
$workhorses = $teams;
unset($workhorses[array_search($temp[0], $teams));
shuffle($workhorses);
$team = $temp[0];
$opponent = array_shift($workhorses);
$game[$week][$games] = $team . ' vs' . $opponent;
$games++;
}
}
Question below copied from above.
Correct me if I get this wrong, but if all teams have to play on the same regular basis, is it even possible to have all teams play the same amount of matches, if there is an odd number of teams? – Yoshi May 3 '11 at 15:05
Michelle,
The number of teams you are trying to pair-up (in this case 8 teams for 16 weeks) can be a daunting task, and is just the beginning of the "scheduling process". Once the correct, balanced team pairings have been determined, it's just the beginning of putting a schedule together for distribution. Next, a list of the 4 weekly time slots includes the; day of the week, start time and location name for each time slot for the whole 16 week season. Comment: What would be most helpful for you is to get an 8 team scheduling matrix that has balanced opponent, and home & away status. It makes a big difference in the quality of a schedule. It's important to evenly distribute early and late time slots, equal home & away status, and equal team distribution with opponents. Most of the balance is accomplished by using a balanced team pair matrix.
After 35 years of teaching, coaching and scheduling sports in the Boston area, I can offer the following information. Creating league or game schedules for sports organizations seems to be a never ending task shared by many and is repeated over and over as the ages of the participants grow and those running the leagues change, the learning curve associated with creating schedules is significant for those who take over.
With that said, I am amazed at how many highly educated mathematical wizards are involved with trying to come up with the perfect solution (algorithm) that will solve one's scheduling problem. Myself and a friend (who is a mathematical/programmer genius) over a period of 3 years created software that perfectly balances all the important components when creating schedules for 4 to 22 teams. What we learned is that there is no algorithm that can handle all the possible variables that are added to the normal variables to create balanced schedules. What I am saying is there are just as many "what ifs" as there are mathematical permutations and combinations that deal with just creating a team matrix listing opponents and home & visitor status of games.
For example: Let's create a perfectly balanced schedule for an 9 team division playing 4 games a week. After nine weeks all teams have played played 8 games, all have had 1 bye, all have played two times in each of the 4 time slots, and all have been scheduled as the home team 4 times and the visitor team 4 times.
What more could anybody want? Well now comes the fun. Because the 4 time slots you chose has 2 games each Saturday, and 2 games each Sunday, the first problem pops up (after the schedules are created, published and passed out, when 2 coaches from 2 different teams call and say they work Saturdays, can you move our games to Sundays? Sure, I can do that. I'll just make the changes, re-publish and re-distribute the schedules.
After the new schedules are distributed, several days later, a different coach calls up and says, "Hey, you moved some of my games to Saturday, I work Saturdays.., move them back". The phone rings again. This time a it's a coach from another team and says they are in a tournament the 5th week of the schedule and can't play that week. Finally the last call comes in from yet another coach. He says the parents of one of his players teaches CCD classes Sunday afternoons, and half of his team is in the CCD class and wants to move all our Sunday games to Saturday. Enough!
My point is no matter what you do or how perfect a schedule is, the best solution is to find out as many of the player/coach team limitations or restrictions before you assign the playing days and time slots to any schedule. These unpredictable variables makes a mess out of a perfect schedule. People do get angry and complain when undesirable schedules are distributed. When a schedule is bad enough, some parents won't sign their youngster to play the following year. This happens when you have a young family with two or three small children, and Dad's work limits his ability to be there. When there is an early morning game, I think you can see the difficulty for Mom's when it all falls on her shoulders.
For those that are new to scheduling, stay with it. It gets better over time after you gain
a little experience dealing with the problems. If you purchase a scheduling software program to calculate team pairs, be careful. Insist on seeing a full single round robin of the schedule they create. Check for the things described above (about balance and distribution).
Bob R
Given a table of teams, say
team (
teamname
);
And a table of fixtures
fixture (
date;
);
With the relationship decomposed by 'playing'
playing (
fixture_date.
teamname
);
Then it's would simply be a matter of iterating through each date, then team and selecting a team at random who does not already have a fixture for that date, and who have not played the selected team (or not played the selected team recently).
Although a simpler solution would be to have team[n] (where n is 0....number of teams -1) play team[(n+(number of teams)) % X] for varying values of X.