I have a feeling there's a ridiculously simple solution to the issue I'm having, but I don't know enough about the intricacies of array functions to figure it out 🙁 It has to do with sorting through $_POST values such that those that edit an existing record get sent to an UPDATE query, while those that generate a new one go to INSERT. See the attached screenshot of my form-in-progress - basically a matrix of stations to sign up for by open time blocks (the numbers in the table cells are IDs for slot, station, etc).

Here's the code:

<?php
	$course = $_POST['course'];
	$week = $_POST['week'];
	$dayID = $_POST['day'];
	$time = $_POST['time'];
	$time = array_diff($time, array('null')); //remove null values
	$station = $_POST['station'];
	$station = array_diff($station, array('blank')); //remove null values
	$slot = $_POST['slot'];
	$slot = array_diff($slot, array('null')); //remove null values

if (isset($slot)) {
	foreach ($slot as $slotID) {
		foreach ($station as $stnExpID) {
		$stnExpID = explode('-',$stnExpID); //split the stationID from the expID
		$stationID = $stnExpID[0];
		$expID = $stnExpID[1];
			foreach ($time as $timeID) {
				echo "UPDATE slotTest SET stationID=$stationID, expID=$expID, timeID=$timeID, open=1 WHERE slotID=$slotID;";
				echo "<br/>";
			}
		}
	}
} else {
	echo "<br />";
	$query = "INSERT INTO slotTest(courseID,weekID,dayID,timeID,stationID,expID,open) VALUES <br />(";
	foreach ($station as $stnExpID) {
		$stnExpID = explode('-',$stnExpID); //split the stationID from the expID
		$stationID = $stnExpID[0];
		$expID = $stnExpID[1];
		foreach ($time as $timeID) {
			$query .= "$course,$week,$dayID,$timeID,$stationID,$expID,1)";
			$query .= ",<br/>(";
		}
	}
	$query = substr($query, 0, -2);  // strips the last ,( characters
	$query .= ";";
	echo $query;
	//echo makeSlot($query);
}

?>

...and here's an example of what it generates:

UPDATE slotTest SET stationID=1, expID=1, timeID=1, open=1 WHERE slotID=43;
UPDATE slotTest SET stationID=1, expID=1, timeID=2, open=1 WHERE slotID=43;
UPDATE slotTest SET stationID=2, expID=2, timeID=1, open=1 WHERE slotID=43;
UPDATE slotTest SET stationID=2, expID=2, timeID=2, open=1 WHERE slotID=43;
UPDATE slotTest SET stationID=3, expID=4, timeID=1, open=1 WHERE slotID=43;
UPDATE slotTest SET stationID=3, expID=4, timeID=2, open=1 WHERE slotID=43;
UPDATE slotTest SET stationID=1, expID=1, timeID=1, open=1 WHERE slotID=44;
UPDATE slotTest SET stationID=1, expID=1, timeID=2, open=1 WHERE slotID=44;
UPDATE slotTest SET stationID=2, expID=2, timeID=1, open=1 WHERE slotID=44;
UPDATE slotTest SET stationID=2, expID=2, timeID=2, open=1 WHERE slotID=44;
UPDATE slotTest SET stationID=3, expID=4, timeID=1, open=1 WHERE slotID=44;
etc.

The problem is pretty glaring - the INSERT query doesn't work at all, and the UPDATE repeats itself where it shouldn't. I can see why the latter is happening - because of the nested foreach loops - but I can't for the life of me figure out what method to use instead. All I want it to do is:

1) Check if slot exists - if yes, write the associated values for station, experiment, and time...if not...
2) Take whatever station, experiment, and time values are left over and create new slots.

There's got to be a better way to do this, and I'd be most grateful for any advice.

    If you are using a MySQL database you can circumvent that issue by using a REPLACE query - it acts as an UPDATE if a record is already there and as an INSERT ohterwise.

    Bjom

      And there is also INSERT ... ON DUPLICATE KEY ...

        Thanks a million! I didn't even know about those functions, and from reading the docs, it seems ON DUPLICATE KEY is what I should go with (since I have foreign key constraints). However, my loop logic still needs to be fixed and I'm not sure how:

        foreach ($station as $stnExpID) {
        		$stnExpID = explode('-',$stnExpID); //split the stationID from the expID
        		$stationID = $stnExpID[0];
        		$expID = $stnExpID[1];
        		//I know the line below is illegal syntax, but is there an equivalent function that does the same thing?
        		foreach ($time as $timeID) && foreach ($slot as $slotID) {
        			$query .= "$slotID,$course,$week,$dayID,$timeID,$stationID,$expID,1)";
        			$query .= ",(";
        		}

        See, the total slots (whether existing or new) are equal to number of open stations multiplied by number of open times. I can't use a counter based on total slots because open times and open stations always vary - the attempt below:

        for ($i=0;$i<=$numSlots;$i++) {
        		$stnExpID = explode('-',$station[$i]);
        		$stationID = $stnExpID[0];
        		$expID = $stnExpID[1];
        		print_r($stnExpID);
        		$timeID = $time[$i];
        		$slotID = $slot[$i];
        		$query .= "$slotID,$course,$week,$dayID,$timeID,$stationID,$expID,1)";
        		$query .= ",(";
        	}

        ...doesn't work because $time[$i] by itself generates undefined indexes if the number of times per sae is less than number of total slots. I tried this fix:

        if (isset($time[$i])) {
        			$timeID = $time[$i];
        		} else {
        			reset($time);
        			$timeID = current($time);
        		}

        ...but it doesn't work either. So is there some kind of function that's equivalent to combining two foreach loops into one, rather than nesting one inside the other?

          there are a number of things you can do. I'm not exactly sure, what you want to achieve, so it's hard to figure out what to suggest.

          If the two arrays "match" i.e. that you need element 1 from array1 and element 1 from array 2 then element 2 from array 1 with element 2 from array 2 and so forth you can advance one array with the foreach and the other with next() like so:

          foreach ($array1 as $value) {
          next($array2);
          echo $value, current($array2);
          //which is the same as
          echo current($array1), current($array2);
          }

          if the arrays do not match - can you make them match?

          Anyway - a little more background and I can hopefully come up with something adequate.

            It's kind of hard to explain, but this screenshot might clear things up: http://ots.dreamhost.com/images/labtable.png

            There are 9 possible times and 15 possible stations. Each time dropdown menu has the same name, "time[]", as do the stations: "station[]" This makes $_POST['time'] an array with a min size of 1 value and max size of 9, while station/experiment has a min size of 1 value and max size of 15 (depending, of course, on what the enduser selects).

            Example: 3 time blocks for 2 stations makes count('$POST['time'])=3, count[$POST['station']]=2, and count($_POST['slot'])=6 (while time and station are drop-down menus, slot is a hidden input in each table cell, filled in with either an existing slotID or null).

            So to answer your question, no, I don't think I can make these arrays match - I need a way to iterate through each slot and insert the appropriate values from the time and station arrays, no matter how few or how many there are, repeating them when needed. Hopefully this makes more sense.

              this doesnt seem to make sense to me: let's say i choose 3 stations. then I choose 4 times....effectively I have now chosen 12 combinations. when I add a time I add it for all stations, and when I add another station, it will be added with all times... there might be a problem in the interface design, that needs to be addressed first...

              but in case this is exactly what you want: it's actually pretty easy to realize the combination with 2 nested foreachs

                let's say i choose 3 stations. then I choose 4 times....effectively I have now chosen 12 combinations. when I add a time I add it for all stations, and when I add another station, it will be added with all times

                Yes, that is what happens. When I said "arrays don't match", I meant that there are always more items in the slot array than JUST the station array or time array.

                  is there a definitive order in that slot array, or do the slotIDs carry the information of the slots' position?

                    I think there's a definitive order in the slot array, since the slodIDs are pulled in the order that they match station/times. If it helps, here's some of the code I used to build the interface:

                    <tr class="topRow">
                    	<td width="125"><h4>Station &amp; Experiment</h4></td>
                    	<?php
                    		for ($i=0;$i<9;$i++) {
                    			echo "<td>\n";
                    			// Get all times used for this course, week, and day, provided they exist
                    			$query = "SELECT timeID FROM slotTest WHERE courseID={$course} AND weekID={$week} AND dayID={$dayID} GROUP BY timeID";
                    			$result = getSlots($query);
                    			if ($result && mysql_num_rows($result)>0) {
                    				$usedTimes = array();
                    				while ($row=mysql_fetch_array($result,MYSQL_ASSOC)) {
                    					$usedTimes[] = $row['timeID'];
                    				}
                    			}
                    			echo "<select name='time[]'>\n";
                    			echo "<option value='null'>Choose time...</option>\n";
                    			$result = getTimes();
                    			while($row=mysql_fetch_array($result,MYSQL_ASSOC)) {
                    				echo "<option ";
                    					if (isset($usedTimes[$i]) && $row['timeID']==$usedTimes[$i]) {
                    						echo "selected='selected' ";
                    					}
                    				echo "value='{$row['timeID']}'>" . $row['time'] . "</option>\n";
                    			} 
                    			echo "</select>\n";
                    			echo "</td>\n";
                    		} ?>
                    </tr> <!-- end topRow -->
                    <?php
                    	for ($j=1;$j<=15;$j++) {
                    		echo "<tr>\n";
                    		echo "<td>\n";
                    		echo "<h4>Station {$j}</h4>\n";
                    		// Finds the experiment (if any) already assigned to Station
                    		$query = "SELECT expID FROM slotTest WHERE courseID={$course} AND weekID={$week} AND dayID={$dayID} AND stationID={$j}";
                    		$result = getSlots($query);
                    		if ($result && mysql_num_rows($result)>0) {
                    			$row = mysql_fetch_array($result,MYSQL_ASSOC); //not a while loop because there's only 1 exp per station 
                    			$usedExp = $row['expID'];
                    		} else {
                    			$usedExp = NULL;
                    		}
                    		echo "<select name='station[]'>";
                    			echo "<option value='blank'>Select experiment...</option>\n";
                    			$result = getExp($course);
                    			while ($row=mysql_fetch_array($result,MYSQL_ASSOC)) {
                    				echo "<option ";
                    					if ($row['expID']==$usedExp) {
                    						echo "selected ";
                    					}
                    				echo "value='{$j}-{$row['expID']}'>" . $row['expName'] . "</option>\n";
                    			}
                    		echo "</select>\n";
                    		echo "</td>\n";
                    		// This builds all the other table cells
                    		for ($k=0;$k<9;$k++) {
                    			echo "<td>";
                    			if (isset($usedTimes[$k])) {
                    				$query = "SELECT slotID FROM slotTest WHERE courseID={$course} AND weekID={$week} AND dayID={$dayID}";
                    				$query .= " AND stationID={$j} AND timeID={$usedTimes[$k]}";
                    				$result = getSlots($query); //get existing slots
                    				if ($result && mysql_num_rows($result)>0) {
                    					$row = mysql_fetch_array($result,MYSQL_ASSOC);
                    					echo "<input type='hidden' name='slot[]' value='{$row['slotID']}' />";
                    				} else {
                    					if (isset($usedExp)) {
                    						echo "<input type='hidden' name='slot[]' value='null' />";
                    					} else {
                    						echo "<input type='hidden' name='slot[]' value='null' />";
                    					}
                    				}
                    			} else {
                    				echo "<input type='hidden' name='slot[]' value='null' />";
                    			}
                    			echo "</td>";
                    		}
                    		echo "</tr>\n";

                      Or, maybe it's better if I describe step-by-step what the loops are supposed to do:

                      While the array pointer is at the CURRENT station:
                      -->Get first time for this station
                      -->Get first slot ID if it exists, if not, write NULL
                      -->Go to next slot/time combo
                      -->Have we run out of slots/times for this station? If so...
                      Move to the NEXT station
                      -->repeat above steps

                      It seems straightforward enough, but I just can't figure what syntax/method to use...

                        Write a Reply...