loop within a loop for updating db record - php

I have a deals table with the following data:
dealID | date | followUP | user
1 |2012-10-15 | Yes |
2 |2012-12-24 | Yes |
3 |2013-01-05 | |
4 |2013-02-02 | Yes |
5 |2013-02-02 | Yes |
And a users table with my users list
userID | name
1 | john
2 | eric
3 | anne
What I would like to do is to query the first table that has followUP set as 'YES' then from the result assign a user to them in sequence from the users table so my final deals table will look like this
dealID | date | followUP | userID
1 |2012-10-15 | Yes | 1
2 |2012-12-24 | Yes | 2
3 |2013-01-05 | |
4 |2013-02-02 | Yes | 3
5 |2013-02-02 | Yes | 1
I know its a loop but for some reason i cant figure out how to setup the second loop to assign the value of the users. Any help would be appreciated.

First get your user IDs into an array so it looks:
$uids = array(1, 2, 3);
Then, when reading the records from deals table compose update queries like so:
$follow_up_user_idx = 0;
$update_queries = array();
while($row=mysqli_fetch_assoc($result)) {
// ... do whatever you need to
if($row['followUP'] != 'Yes') continue;
$update_queries[] = "UPDATE `deals` SET `user` = '" . $uids[$follow_up_user_idx] . "'
WHERE `dealID` = '" . $row['dealID'] . "' LIMIT 1";
$follow_up_user_idx++;
if($follow_up_user_idx > count($uids) - 1) $follow_up_user_idx = 0;
}
Now you have all update queries. Just execute them:
foreach($update_queries as $uq) {
mysqli_query($link, $uq);
}

You will have to follow a series of steps to achieve what you have mentioned.
1) Fetch all the records from database where followUP is 'Yes'.
Lets say that first table is deals. So, fetch all records where followUP is 'Yes'.
Lets say, you have result in $deals_details.
2) Fetch all the users(name) from database.
Lets say that second table is users. So, fetch all users.
Lets say, you have all users' names in $users_details array.
Get a count of total users in system in seperate variable say $users_count.
3) Loop through $deals_details and assign each user one-by-one sequentially from $users_details.
$i = 0;
foreach($deals_details as $keyDD => $valueDD){
$user = $users_details[$i];
$i++;
if($i == $users_count)
$i = 0;
$query = "update `deals` set user = '".$user."' where dealID = '".$valueDD['dealID']."'";
//fire query
//$link is connection variable.
mysqli_query($link, $query);
}

Table user
+---------------+---------------+------------+
| user_id | username | user_level |
+---------------+---------------+------------+
| 1 | superadmin | admin |
| 2 | subadmin | admin |
| 3 | team1 | team |
| 4 | team2 | team |
| 5 | team3 | team |
| 6 | customer1 | customer |
| 7 | customer2 | customer |
| 8 | customer3 | customer |
| 9 | customer4 | customer |
+---------------+---------------+------------+
Table complaint:
+---------------+---------------+------------+
| complaint_id | complaint | user_id |
+---------------+---------------+------------+
| 1 | os issue | 7 |
| 2 | USB issue | 8 |
| 3 | OS currepted | 7 |
| 4 | HD issue | 9 |
| 5 | DVD issue | 6 |
| 6 | SW problem | 9 |
| 7 | Network issue| 9 |
| 8 | system issue | 6 |
+---------------+---------------+------------+
Table assign_work
+---------------+------------+
| complaint_id | user_id |
+---------------+------------+
| 1 | 3 |
| 2 | 4 |
| 3 | 5 |
| 4 | 3 |
| 5 | 4 |
| 6 | 5 |
| 7 | 3 |
| 8 | 4 |
+---------------+------------+
When customer raise the complaint data should save in complaint table also that last
complaint_id should save in assign_work table at the same time
user_id also save sequencially, fetch from user table who are the team that person id only.
I m new in ph please any one help me.

This may be a poor design decision. Without knowing more about your application, I'd be tempted to wait for a user to become available/request a deal, then assign to them (from a queue) the next deal requiring follow-up. Even if you have good reasons to assign users before they are "available", you might consider doing so upon deal creation/modification based on some appropriate business logic (e.g. maintaining a queue of users to be assigned to the next deal).
Indeed, there's no particularly nice way of performing this operation with a simple UPDATE statement. One way to accomplish it purely within the database would be to use a stored procedure (it's not especially concurrency-safe though, as changes to the Users table between closing and reopening the _curUser cursor may cause undesirable effects; one might instead copy the Users to a temporary table for the purposes of this procedure, depending on your desired logic):
DELIMITER //
CREATE PROCEDURE assignDeals() BEGIN
DECLARE _userID, _dealID BIGINT UNSIGNED;
DECLARE _done BOOLEAN DEFAULT FALSE;
DECLARE _curUser CURSOR FOR
SELECT userID
FROM users
ORDER BY userID;
DECLARE _curDeal CURSOR FOR
SELECT dealID
FROM deals
WHERE followUP = 'Yes'
ORDER BY dealID
FOR UPDATE;
DECLARE CONTINUE HANDLER FOR NOT FOUND
SET _done := TRUE;
PREPARE stmt FROM 'UPDATE deals SET userID = ? WHERE dealID = ?';
OPEN _curUser;
OPEN _curDeal;
readDeal: LOOP
FETCH _curDeal INTO _dealID;
IF _done THEN
LEAVE readDeal;
END IF;
FETCH _curUser INTO _userID;
IF _done THEN
SET _done := FALSE;
CLOSE _curUser;
OPEN _curUser;
FETCH _curUser INTO _userID;
IF _done THEN
SIGNAL SQLSTATE VALUE '45000' SET
MESSAGE_TEXT = 'No users';
LEAVE readDeal;
END IF;
END IF;
SET #userID := _userID, #dealID := _dealID;
EXECUTE stmt USING #userID, #dealID;
END LOOP readDeal;
CLOSE _curUser;
CLOSE _curDeal;
DEALLOCATE PREPARE stmt;
END//
DELIMITER ;
See it on sqlfiddle.

Related

How to update all rows with column = to value except 1, then update that one to another value?

I have a MySQL OFFERS table with an OID, PID and STATUS. STATUS has 3 ENUM values. O A C. (Open, Accepted, Closed). It looks like this:
+---------+-------------+--------+
| oid | pid | status |
+---------+-------------+--------+
| 1 | 1 | o |
| 2 | 1 | o |
| 3 | 1 | o |
| 4 | 2 | o |
+---------+-------------+--------+
All offers are open.
When a user wants to accept an offer, they click a button, which sends the post ID (PID) and the offer ID (OID) to the php file which does the UPDATE statement to the database. I want the statement to update the table to look like this:
+---------+-------------+--------+
| oid | pid | status |
+---------+-------------+--------+
| 1 | 1 | a |
| 2 | 1 | c |
| 3 | 1 | c |
| 4 | 2 | o |
+---------+-------------+--------+
Psudo-PHP-MySQLI statement:
UPDATE offers
SET status='c'
WHERE pid = $_POST['pid'], except WHERE oid = $_POST['oid']
but also SET status='a' WHERE oid = $_POST['oid']
I am new to PHP and MySQLi so I dont know how to structure all of the statements. Is this kind of statement even possible? I know to use prepared statements, but I am just adding the values in here just for simplicity. Thanks!
Use CASE to specify different values to assign depending on a condition.
UPDATE offers
SET status =
CASE oid
WHEN $_POST['oid'] THEN 'a'
ELSE 'c'
END
WHERE pid = $_POST['pid']

Reorder mysql table ROWS on front end, and update backend [duplicate]

I have a table of food items. They have a "Position" field that represents the order they should appear in on a list (listID is the list they are on, we don't want to re-order items on another list).
+--id--+--listID--+---name---+--position--+
| 1 | 1 | cheese | 0 |
| 2 | 1 | chips | 1 |
| 3 | 1 | bacon | 2 |
| 4 | 1 | apples | 3 |
| 5 | 1 | pears | 4 |
| 6 | 1 | pie | 5 |
| 7 | 2 | carrots | 0 |
| 8,9+ | 3,4+ | ... | ... |
+------+----------+----------+------------+
I want to be able to say "Move Pears to before Chips" which involves setting the position of Pears to position 1, and then incrementing all the positions inbetween by 1. so that my resulting Table look like this...
+--id--+--listID--+---name---+--position--+
| 1 | 1 | cheese | 0 |
| 2 | 1 | chips | 2 |
| 3 | 1 | bacon | 3 |
| 4 | 1 | apples | 4 |
| 5 | 1 | pears | 1 |
| 6 | 1 | pie | 5 |
| 7 | 2 | carrots | 0 |
| 8,9+ | 3,4+ | ... | ... |
+------+----------+----------+------------+
So that all I need to do is SELECT name FROM mytable WHERE listID = 1 ORDER BY position and I'll get all my food in the right order.
Is it possible to do this with a single query? Keep in mind that a record might be moving up or down in the list, and that the table contains records for multiple lists, so we need to isolate the listID.
My knowledge of SQL is pretty limited so right now the only way I know of to do this is to SELECT id, position FROM mytable WHERE listID = 1 AND position BETWEEN 1 AND 5 then I can use Javascript (node.js) to change position 5 to 1, and increment all others +1. Then UPDATE all the records I just changed.
It's just that anytime I try to read up on SQL stuff everyone keeps saying to avoid multiple queries and avoid doing syncronous coding and stuff like that.
Thanks
This calls for a complex query that updates many records. But a small change to your data can change things so that it can be achieved with a simple query that modifies just one record.
UPDATE my_table set position = position*10;
In the old days, the BASIC programming language on many systems had line numbers, it encouraged spagetti code. Instead of functions many people wrote GOTO line_number. Real trouble arose if you numbered the lines sequentially and had to add or delete a few lines. How did people get around it? By increment lines by 10! That's what we are doing here.
So you want pears to be the second item?
UPDATE my_table set position = 15 WHERE listId=1 AND name = 'Pears'
Worried that eventually gaps between the items will disappear after multiple reordering? No fear just do
UPDATE my_table set position = position*10;
From time to time.
I do not think this can be conveniently done in less than two queries, which is OK, there should be as few queries as possible, but not at any cost. The two queries would be like (based on what you write yourself)
UPDATE mytable SET position = 1 WHERE listID = 1 AND name = 'pears';
UPDATE mytable SET position = position + 1 WHERE listID = 1 AND position BETWEEN 2 AND 4;
I've mostly figured out my problem. So I've decided to put an answer here incase anyone finds it helpful.
I can make use of a CASE statement in SQL. Also by using Javascript beforehand to build my SQL query I can change multiple records.
This builds my SQL query:
var sql;
var incrementDirection = (startPos > endPos)? 1 : -1;
sql = "UPDATE mytable SET position = CASE WHEN position = "+startPos+" THEN "+endPos;
for(var i=endPos; i!=startPos; i+=incrementDirection){
sql += " WHEN position = "+i+" THEN "+(i+incrementDirection);
}
sql += " ELSE position END WHERE listID = "+listID;
If I want to move Pears to before Chips. I can set:
startPos = 4;
endPos = 1;
listID = 1;
My code will produce an SQL statement that looks like:
UPDATE mytable
SET position = CASE
WHEN position = 4 THEN 1
WHEN position = 1 THEN 2
WHEN position = 2 THEN 3
WHEN position = 3 THEN 4
ELSE position
END
WHERE listID = 1
I run that code and my final table will look like:
+--id--+--listID--+---name---+--position--+
| 1 | 1 | cheese | 0 |
| 2 | 1 | chips | 2 |
| 3 | 1 | bacon | 3 |
| 4 | 1 | apples | 4 |
| 5 | 1 | pears | 1 |
| 6 | 1 | pie | 5 |
| 7 | 2 | carrots | 0 |
| 8,9+ | 3,4+ | ... | ... |
+------+----------+----------+------------+
After that, all I have to do is run SELECT name FROM mytable WHERE listID = 1 ORDER BY position and the output will be as follows::
cheese
pears
chips
bacon
apples
pie

How to display the previous row and next row from varchar value

I have hundreds rows of data. I want to get the previous row and the next row from the current item. I saw many examples here but none solve my problem.
My data key is a set of string (md5) which is unable to compare the greater or lower like the other does. Here's my resources.
---------------------------------------------------
| id| sid | name |
----+----------------------------------+----------|
| 1 | c81e728d9d4c2f636f067f89cc14862c + Mr.A |
----+----------------------------------+----------|
| 2 | eccbc87e4b5ce2fe28308fd9f2a7baf3 | Mr.B |
----+----------------------------------+----------|
| 3 | a87ff679a2f3e71d9181a67b7542122c | Mr.C |<current position
----+----------------------------------+----------|
| 4 | e4da3b7fbbce2345d7772b0674a318d5 | Mr.D |
----+----------------------------------+----------|
| 5 | 1679091c5a880faf6fb5e6087eb1b2dc | Mr.E |
--------------------------------------------------|
So, is there any way to get the previous row (Mr.B) and the next row (Mr.D) with mysql?
I've tried
SELECT * FROM table
WHERE sid < #sid
ORDER BY sid DESC
LIMIT 1
but it's not work because sid is uncomparable.

PHP Unset index if no match

I have two tables that have these columns (I'm only showing revelant ones) :
tasks table
+----+------+
| id | todo |
+----+------+
| 1 | 0 |
| 2 | 1 |
| 3 | 1 |
| 4 | 0 |
| 5 | 1 |
+----+------+
entries table
+----+---------+---------+------+
| id | task_id | user_id | done |
+----+---------+---------+------+
| 1 | 3 | 1 | 1 |
| 2 | 5 | 2 | 1 |
| 3 | 5 | 1 | 1 |
| 4 | 2 | 1 | 0 |
+----+---------+---------+------+
I query these tables and only keep tasks where todo = 1, So I already have the data in a PHP object.
I then have two lists that the user can view : tasks that are to do, and archived (done), and tasks that are to do. I can generate the first list just fine, I'm looping through each task and entries if they have a matching task_id where user_id == $loggeduser && done == 1, and unsetting the index of those that don't match. However, I cannot find a logic to do this with my archive list, as I don't have entries to match. How do I loop my tasks and only keep those that are done, for the user? In this case, for the archive list for user 1, I'm excepting to only keep task id 3 and 5, and for user 2, only keep task id 2.
Thanks.
You can do all this using plain SQL (I suppose you're using some relational database).
This query gives you all the tasks "todo & done". To get the tasks "todo & not done", just change the "e.done = 1" to "e.done = 0". I'm sure you get the idea.
SELECT * FROM tasks t
INNER JOIN entries e ON t.id = e.task_id
AND e.user_id = [logged_user_id]
AND e.done = 1
WHERE
t.todo = 0

Selecting multiple tables MySQL and retrieving different data

I have 4 tables that I need to pull data from. I need to count how many people are signed for a single event and see if a user is applied for an event.
These are my table setups:
TABLE: users
+----+----------+-------+--------+-------+
| id | username | level | class | guild |
+----+----------+-------+--------+-------+
| 1 | example1 | 100 | Hunter | blah |
| 2 | example2 | 105 | Mage | blah2 |
| 3 | example3 | 102 | Healer | blah |
+----+----------+-------+--------+-------+
ID is primary
TABLE: event_randoms
+----+----------+-------+--------+----------+----------+
| id | username | level | class | apped_by | event_id |
+----+----------+-------+--------+----------+----------+
| 1 | random1 | 153 | Hunter | 3 | 3 |
| 2 | random2 | 158 | Healer | 3 | 1 |
| 3 | random3 | 167 | Warrior| 1 | 3 |
+----+----------+-------+--------+----------+----------+
ID is primary
apped_by should be foreign key to users.id
event_id should be foreign key to events.id
TABLE: events
+----+------------+------------+-----------+-----------+-----------+
| id | event_name | event_date | initiator | min_level | max_level |
+----+------------+------------+-----------+-----------+-----------+
| 1 | event1 | date1 | 1 | 100 | 120 |
| 2 | event2 | date2 | 1 | 121 | 135 |
| 3 | event3 | date3 | 1 | 100 | 120 |
| 4 | event4 | date4 | 1 | 150 | 200 |
+----+------------+------------+-----------+-----------+-----------+
ID is primary
TABLE: event_apps
+----+----------+--------------+
| id | event_id | applicant_id |
+----+----------+--------------+
| 1 | 3 | 2 |
| 2 | 4 | 2 |
| 3 | 3 | 1 |
| 4 | 1 | 3 |
+----+----------+--------------+
ID is primary
event_id should be foreign key to events.id
applicant_id should be foreign key to users.id
I will be the first to admit that I am very new to this. I just learned how to use MySQL a few days ago. I can grab stuff from a single table, but I am unsure how to grab from multiple tables.
This is the SQL query I tried
SELECT DD_events.id, event_id, applicant_id, guild, level, class, DD_users.id
FROM DD_events, DD_event_apps, DD_users
WHERE DD_event_apps.event_id = DD_events.id
AND DD_event_apps.applicant_id = DD_users.id
and tried to print_r an array but the array turns up empty.
So a few questions pertain to this:
1: How would I count and display as a number how many people (users and randoms) are signed up for an event?
eg: event 3 should have 4 total (2 users and 2 randoms)
2: How do I see if a particular individual is signed for an event and display text based if they are or not?
eg: user 1 is signed up for event 3 so it would be "Registered" but user 2, who is not signed, would display "Not Registered"
3: I want to display info for who is signed for a particular event in 2 tables, 1 for users and another for randoms.
eg: Event 3 would have 2 users info (username, guild, class, level) under the users table and then 2 random users info (name, class, level, what user applied this person) in the random table.
Any and all help is appreciated even if you can answer 1 part.
I'm thinking this would be your base query:
SELECT
event.id,
app.applicant_id,
usr.guild,
usr.level,
usr.class,
usr.id AS Userid
FROM
DD_events event
JOIN
DD_event_apps app
ON (event.id = app.event_id)
LEFT JOIN
DD_users usr
ON (app.user_id = usr.id)
You can make modifications to this to aggregate it, like so:
SELECT
event.id,
COUNT(app.applicant_id) AS ApplicantCount,
COUNT(DISTINCT usr.guild) AS UniqueGuilds,
COUNT(DISTINCT usr.level) AS UniqueLevels,
COUNT(DISTINCT usr.class) AS UniqueClasses,
COUNT(DISTINCT usr.id) AS UniqueUsers
FROM
DD_events event
JOIN
DD_event_apps app
ON (event.id = app.event_id)
LEFT JOIN
DD_users usr
ON (app.user_id = usr.id)
GROUP BY
event.id
I could write those scripts for you, but I think this provides a good starting point for you to continue from. You'll find that T-SQL is fairly simple when you are trying to get the results you are looking for. Hope this helps!
<?php $query = "SELECT count(*) AS numbuh FROM DD_event_apps WHERE event_id = {$row['id']}";
try
{
// These two statements run the query against your database table.
$stmt = $db->prepare($query);
$stmt->execute();
}
catch(PDOException $ex)
{
// Note: On a production website, you should not output $ex->getMessage().
// It may provide an attacker with helpful information about your code.
die("Failed to run query: " . $ex->getMessage());
}
echo($query);
// Finally, we can retrieve all of the found rows into an array using fetchAll
$count = $stmt->fetchAll();
echo($count['numbuh']); ?>

Categories