I have events each with 50 maximum participants.
Every time a user signs up for an event, his name, email, and mobile no. gets saved in the database. So I am inserting these values whenever a sign up is made: ID, p_name, p_mobile, p_email, p_event the last column is the name of the event.
I need to add a new column called p_max wherein it will automatically increase by 1 for each unique event. A sort of counter.
So I can then check if the maximum is reached by getting the p_max column of the last row with the event name.
I hope I explained the question clearly. Feel free to ask questions for clarification.
Thanks in advance!
If I understand the question correctly, you would need to check for the number of users for a specific event before you confirm the sign-up.
So you would not need a new column (or it would be a column in the events table where you can specify the maximum number of participants per event), you need to check how many users there already are for that specific event.
You could use something like this to query the database:
SELECT COUNT(*) as number_of_participants FROM users WHERE p_event = YOUR_EVENT_ID
First, you want an events table, that has the maximum number of participants.
Then you need a before insert trigger on the participants table. This trigger would fail if the following is true:
select (count(*) >= max(e.maxparticipants))
from participants p join
events e
on p.event = e.event
where event = new.event;
These will limit the number of participants in an event.
You can also implement this in a stored procedure rather than a trigger, if you wrap your insert logic in stored procedures.
Or, you can implement this logic directly in your application, although I think it is safer to implement it in the database. If you do so, consider this statement:
insert into participants(<columns go here>)
select <column values go here>
from dual
where (select max(e.maxparticipants) - COUNT(*))
from participants p join
events e
on p.event = e.event
where event = THEEVENT
) > 0;
This insert will not insert any rows once the maximum has been reached.
Related
I have 1 mysql table where it has thousands of rows. I use this as a transaction history for my users. I also query this table on the same page for a sum of earnings per product. here are my two mysql calls;
$earnperproduct = mysqli_query($con,"SELECT product, SUM(amount) AS totalearn FROM wp_payout_history WHERE user=$userid GROUP BY product");
$result = mysqli_query($con,"SELECT * FROM wp_payout_history WHERE user=$userid ORDER BY date DESC");
my fear is that as the table grows, the $earnperproduct call will become too intensive and slow down page loading. Therefore instead of doing a sum command every time the page loads, i think it would be easier to update a summary (example wp_summary_table) whenever wp_payout_history is changed to replace past values with new SUM(AMOUNT)values per user and product; and thus query something like this;
$earnperproduct = mysqli_query($con,"SELECT * FROM wp_payout_summary_table WHERE user=$userid ORDER BY product DESC");
TL;DR
What is the best method to go about updating a table using the $earnedperproduct style call? would I be better using mysql event scheduler or a php script with a crontab? Is there any tutorials that can help me create either option for my needs?
Both the control mechanisms you mention use time as the trigger for an action. But your description says that you really want to trigger an action when the data changes. And in a relational database the best way to trigger an action when data is changed is with a ....trigger. Which makes your question a duplicate of this.
Arguably it may be more efficient to snapshot the transactions, then something like....
[INSERT INTO summary_table (user, total_amount, last_id) ]
SELECT
user, SUM(amount), MAX(id)
FROM (
SELECT a.user, a.total_amount AS amount, a.last_id
FROM summary_table a
WHERE a.user=$user_id
AND last_id=(SELECT MAX(b.last_id)
FROM summary_table b
WHERE b.user=$user_id)
UNION
SELECT h.user, h.amount, h.id
FROM wp_payout_history h
WHERE h.user=$user_id
AND h.id>(SELECT MAX(c.last_id)
FROM summary_table c
WHERE c.user=$user_id)
) ilv
GROUP BY user;
...then it doesn't really matter what you use to refresh the history - the query will always give you an up to date response. If you go down this route then add a dummy integer column in the summary table and add 0 as unaggregatedrows to the second SELECT and SUM(1) to the 4th SELECT to work out when it will be most efficient to update the summary table.
I want to create a statistics page where i can count the number of reasons given in a table ...The reasons are created dynamically and stored in another table.
Table1 contains all the reasons which populate a drop down box...
Table2 contains the entries given by the user one of the columns is the reason value.
I would like to count the amount of times each reason appears .
Thankyou for your time and help
Looks like simply group statement:
select
reason.name reason,
count(*) count
from entry, reason
where
entry.reason = reason.id and
entry.time > now() - interval 7 day -- you probably need some filter
group by reason.id
So, I have a table A that each time a user sends an image, a record is created storing the time it was uploaded, the username of the user and the image number out of all the images uploaded over time.
I need to make a second table B that will store the amount of images uploaded per user and the user name. I need this table B to be updated when a new entry is generated in A.
I found that a trigger function can be created, nevertheless I'm having a rough time finding an example that will suit my needs.
Does anyone know a way of doin what I want?
Just update b table with a select count of total inserted records on a from current user NEW.userid (userid is your column name or whatever name you have there, and NEW is a fixed mySql reference for the current values to be inserted):
CREATE TRIGGER img_sum AFTER INSERT ON a
FOR EACH ROW SET b.total = (SELECT COUNT(*) FROM a WHERE a.userid=NEW.userid)
WHERE b.userid = NEW.userid;
From what you have described i don't think you need a second table. You can just count the number of time a user name has occurred, and you will get the number of images that user has uploaded.
You can get the count doing something like that
SELECT COUNT(DISTINCT username) FROM table_name;
If you still need to create 2 tables, you might want to take a look at procedures and how they work.
Let's say we have 3 tables for this case:
- users(id, username, email ....),
- user_images(id, userId, image_num, date_uploaded)
- user_images_count(id, user_name, images_count)
The user_images_count is initially empty. We have to fill it up by such query:
INSERT into user_images_count(user_name, images_count)
SELECT (select username from users where ui.userId = id) as username, count(userId) as counter FROM `user_images` ui group by ui.userId;
Then, we must immediately create the trigger that will process every INSERT operation into user_images table.
CREATE TRIGGER `count_user_images` AFTER INSERT ON `user_images`
FOR EACH ROW begin
declare u_name tinytext default "";
set u_name = (select username from users where id = NEW.userId limit 1);
if(u_name != "") then
update user_images_count set images_count = images_count + 1 where user_name = u_name;
end if;
end
This two queries (user_images_count fulfillment and trigger creation must be performed in one transaction, one by one).
I've created similar triggers on my local databases. They work pretty good. )))
I have a web application that stores points in a table, and total points in the user table as below:
User Table
user_id | total_points
Points Table
id | date | user_id | points
Every time a user earns a point, the following steps occur:
1. Enter points value to points table
2. Calculate SUM of the points for that user
3. Update the user table with the new SUM of points (total_points)
The values in the user table might get out of sync with the sum in the points table, and I want to be able to recalculate the SUM of all points for every user once in a while (eg. once a month). I could write a PHP script that could loop through each user in the user table and find the sum for that user and update the total_points, but that would be a lot of SQL queries.
Is there a better(efficient) way of doing what I am trying to do?
Thanks...
A more efficient way to do this would be the following:
User Table
user_id
Points Table
id | date | user_id | points
Total Points View
user_id | total_points
A view is effectively a select statement disguised as a table. The select statement would be: SELECT "user_id", SUM("points") AS "total_points" FROM "Points Table" GROUP BY "user_id". To create a view, execute CREATE VIEW "Total Points View" AS <SELECT STATEMENT> where SELECT STATEMENT is the previous select statement.
Once the view has been created, you can treat it as you would any regular table.
P.S.: I don't know that the quotes are necessary unless your table names actually contain spaces, but it's been a while since I worked with MySQL, so I don't remember it's idiosyncrasies.
You have to user Triggers for this, to make the users total points in sync with the user_points table. Something like:
Create Trigger UpdateUserTotalPoints AFTER INSERT ON points
FOR EACH ROW Begin
UPDATE users u
INNER JOIN
(
SELECT user_id, SUM(points) totalPoints
FROM points
GROUP BY user_id
) p ON u.user_id = p.user_id
SET u.total_points = p.totalPoints;
END;
SQL Fiddle Demo
Note that: As noted by #FireLizzard, if these records in the second table, are frequently updated or delted, you have to have other AFTER UPDATE and AFTER DELETE triggers as well, to keep the two tables in sync. And in this case the solution that #FireLizzard will be better in this case.
If you want it once a month, you can’t deal with just MySQL. You have too « logic » code here, and put too logic in database is not the correct way to go. The trigger of Karan Punamiya could be nice, but it will update the user_table on every insert in points table, and it’s not what you seem to want.
For the fact you want to be able to remove points, just add bsarv new negated rows in points, don’t remove any row (it will break the history trace).
If you really want it periodically, you can run a cron script that does that, or even call your PHP script ;)
I have a voting script which pulls out the number of votes per user.
Everything is working, except I need to now display the number of votes per user in order of number of votes. Please see my database structure:
Entries:
UserID, FirstName, LastName, EmailAddress, TelephoneNumber, Image, Status
Voting:
item, vote, nvotes
The item field contains vt_img and then the UserID, so for example: vt_img4 and both vote & nvotes display the number of votes.
Any ideas how I can relate those together and display the users in order of the most voted at the top?
Thanks
You really need to change the structure of the voting table so that you can do a normal join. I would strongly suggest adding either a pure userID column, or at the very least not making it a concat of two other columns. Based on an ID you could then easily do something like this:
select
a.userID,
a.firstName,
b.votes
from
entries a
join voting b
on a.userID=b.userID
order by
b.votes desc
The other option is to consider (if it is a one to one relationship) simply merging the data into one table which would make it even easier again.
At the moment, this really is an XY problem, you are looking for a way to join two tables that aren't meant to be joined. While there are (horrible, ghastly, terrible) ways of doing it, I think the best solution is to do a little extra work and alter your database (we can certainly help with that so you don't lose any data) and then you will be able to both do what you want right now (easily) and all those other things you will want to do in the future (that you don't know about right now) will be oh so much easier.
Edit: It seems like this is a great opportunity to use a Trigger to insert the new row for you. A MySQL trigger is an action that the database will make when a certain predefined action takes place. In this case, you want to insert a new row into a table when you insert a row into your main table. The beauty is that you can use a reference to the data in the original table to do it:
CREATE TRIGGER Entries_Trigger AFTER insert ON Entries
FOR EACH ROW BEGIN
insert into Voting values(new.UserID,0,0);
END;
This will work in the following manner - When a row is inserted into your Entries table, the database will insert the row (creating the auto_increment ID and the like) then instantly call this trigger, which will then use that newly created UserID to insert into the second table (along with some zeroes for votes and nvotes).
Your database is badly designed. It should be:
Voting:
item, user_id, vote, nvotes
Placing the item id and the user id into the same column as a concatenated string with a delimiter is just asking for trouble. This isn't scalable at all. Look up the basics on Normalization.
You could try this:
SELECT *
FROM Entries e
JOIN Voting v ON (CONCAT('vt_img', e.UserID) = v.item)
ORDER BY nvotes DESC
but please notice that this query might be quite slow due to the fact that the join field for Entries table is built at query time.
You should consider changing your database structure so that Voting contains a UserID field in order to do a direct join.
I'm figuring the Entries table is where votes are cast (you're database schema doesn't make much sense to me, seems like you could work it a little better). If the votes are actually on the Votes table and that's connected to a user, then you should have UserID field in that table too. Either way the example will help.
Lets say you add UserID to the Votes table and this is where a user's votes are stored than this would be your query
SELECT Users.id, Votes.*,
SUM(Votes.nvotes) AS user_votes
FROM Users, Votes
WHERE Users.id = Votes.UserID
GROUP BY Votes.UserID
ORDER BY user_votes
USE ORDER BY in your query --
SELECT column_name(s)
FROM table_name
ORDER BY column_name(s) ASC|DESC