http://sqlfiddle.com/#!9/b729e5/1
In my reservation-system users should be able to sign up to multiple events at different time slots, each time slot has a limit of participants.
How can I connect these two tables in one MySQL-Query to get the number of places reserved per time slot of an event?
This data will be sent to php to show the user on a reservation page which time slot has free places and which is already booked up.
you may change the design of the reservations Table to be like this :
reservation_id | user_id | date_of_reservation | event_id | time_slot
then multiple reservations can be multiple rows for the same user ,
then link the two tables reservations and events using user_id + event_id
to test that your data is gethered correctly :
select r.user_id,r.event_id,r.time_slot,e.title
from reservations r,events e
where r.user_id = e.user_id
after that you can device your SQL easily using group by and count
select count(event_id)
from reservations r
where r.user_id = '<specific user>'
/*if you want*/
and time_slot between '' and ''
Fix your table structure first by adding another table like "EventTimeSlot".
Event -> id | host_id | date_of_event | title | description |
EventTimeSlot -> id | event_id | time_slot_name | max_participants |
Reservation -> id | user_id | date_of_reservation | event_id | time_slot_id |
Then make your question clear as I did not understand what you meant by "to get the number of places reserved per time slot of an event?".
Related
I have mysql table as follows:
|id | subject | link | week_number
------------------------------------
| 1 | ABC | link1 | week-1
| 2 | DEF | link2 | week-2
| 3 | GHI | link3 | week-3
------------------------------------
Now I want To show week-1 record to user for one week after login and from his registration date as initial date for week counting....
then in next week, week-1 and week-2 should be visible,
then in next week, week-1, week-2 and week-3 records should be visible.
I am completely blank...so didn't tried any code....
your help or guideline appreciated...
If you have a registration date, just make your live easier and change the column week_number to days_after_reg - and the values to 7,14,21
Then you just need to compare this number with the current offset:
SELECT * from linktable WHERE `days_after_reg` <= datediff(Now(), UserRegistrationDate)
Either insert the user date with a variable, or "join" the tables.
Note that the join has no join condition here, so don't forget to filter on user-id (or name or something).
SELECT l.subject, l.link from linktable l cross join
users u WHERE `l.days_after_reg` <= datediff(Now(), u.registrationDate)
and u.id=5
Hello I think I try here something complicated. Maybe you can help me out here.
I have two tables: earnings and payouts.
Earnings has userid, amount, timestamp as datetime and other stuff. It has just information when user was earning something.
Example:
id | user_id | amount | timestamp |
1 | 2 | 1050 | 31days ago |
2 | 1 | 20 | 10days ago |
3 | 1 | 10 | 9 days ago |
4 | 2 | 10000 | 9 days ago |
...
Payouts has userid, amount, timestamp as datetime and has entries about payouts if a user is above x earnings lets say 1000. Example
id | user_id | payout_amount | timestamp |
1 | 2 | 1050 | 30days ago |
...
To my problem now. I want to COUNT how many payouts are NOT done (who has no entry in payout). This means. I need to compare payouts.timestamp with earnings.timestamp which has same userid and check if there are newer entries then the payouts. If yes then count it how many (so I think here its needed to sum first the earnings). I am not even sure if this is possible.
I can do it also with php if this isn't possible alone with mysql.
For example the result should be: count = 2 because userid 1 has just 30 earnings so he didn't reach the 1000 also he has no entry in payouts table. Userid 2 has 10000 but he still has no payouts because we didn't execute it or make a entry in the payouts table. he just has a old payout and the new earnings isn't paid.
Edit: the 10days ago things are just example. I use there real datetime types
EDIT2: Forget to say I tried this one:
select COUNT(e.amount) FROM earnings e, payouts p where p.payout_timestamp < e.timestamp AND p.user_id = e.user_id GROUP BY p.user_id, e.user_id
and go this:
| Count(e.amount) |
| 2 |
| 1 |
I think that comparing timestamps is not the only way to get result that you need. If these to tables correctly represent history of earnings and payments then you may just sum up total earnings and payments for each user and compare them counting every user_id that has less payments than earnings.
For example:
SELECT user_id, SUM(amount) as amount FROM earnings GROUP BY user_id;
sums up earnings for each user,
SELECT user_id, SUM(payout_amount) as amount FROM payouts GROUP BY user_id;
sums up payments for each user.
Now left join them and count users who has less payments than earnings:
SELECT COUNT(e1.user_id) FROM (SELECT user_id, SUM(amount) as amount FROM earnings GROUP BY user_id) as e1 LEFT JOIN (SELECT user_id, SUM(payout_amount) as amount FROM payouts GROUP BY user_id) as p1 ON e1.amount > p1.amount;
For your tables example my result was:
+-------------------+
| COUNT(e1.user_id) |
+-------------------+
| 2 |
+-------------------+
And to find users with payments not done just use the same query without COUNT() function:
+---------+
| user_id |
+---------+
| 2 |
| 1 |
+---------+
In my opinion this way is more stable because it is possible to have recent payments with less amount than total user earnings at the moment of payment, e.g.:
1) user earned 1000
2) then user earned 2000
3) and after that user been payed 1000
In this situation comparing timestamps without comparing amounts of payments will show you that this user has no payments to be done whereas you still need to pay him 2000.
I am trying to figure out how to rank based on 2 different column numbers in laravel but raw mysql will do. I have a list of videos, these videos are inside of competitions and are given votes if someone likes the video. Each video will have a vote number and a competition number. I am trying to rank based on votes within competition. So for example below I have competition 8, I need the rank of all the videos in that competition based on votes. I then need the same for competition 5 etc.
|rank|votes|competition|
------------------
| 1 | 100 | 8 |
------------------
| 2 | 50 | 8 |
------------------
| 3 | 30 | 5 |
------------------
| 1 | 900 | 5 |
------------------
| 2 | 35 | 5 |
------------------
I have tried various group and selectby methods but nothing seems to work, any ideas?
In Mysql you can use user-defined variables to calculate rank,case statement checks if competition is same as the previous row then increment rank by one if different then assign 1 an order by is needed to have correct rank for the video
SELECT t.*,
#current_rank:= CASE WHEN #current_rank = competition
THEN #video_rank:=#video_rank +1
ELSE #video_rank:=1 END video_rank,
#current_rank:=competition
FROM t ,
(SELECT #video_rank:=0,#current_rank:=0) r
ORDER BY competition desc, votes desc
See Demo
If you are confused with the last extra column you can use a subselect
See Demo
You can use windowing functions:
select
competition, votes, rank() over (partition by competition order by votes desc) as rank
from
table1
I am making something like an announcement board that requires readers to acknowledge that they read it, and was wondering if there is a more efficient way of doing this.
I have 3 Tables on MySQL side:
+-----------------+ +-----------------+ +-----------------+
| Announcements | | Acknowledgement | | User |
+-----------------+ +-----------------+ +-----------------+
| announce_id | | ack_id | | user_id |
| announce_msg | | announce_id | | user_name |
| ... | | user_id | | ... |
+-----------------+ +-----------------+ +-----------------+
When a user "reads" the announcement (by clicking a button), Acknowledgment table will be inserted with the Announcement ID and User ID. When a second user "reads" the same announcement, Acknowledgement table will be inserted again with same Announcement ID and the second User ID and so on...
+--------------------------------+
| Acknowledgement |
+--------+-------------+---------+
| ack_id | announce_id | user_id |
+--------+-------------+---------+
| 1 | 1 | 1 |
| 2 | 1 | 4 |
| 3 | 1 | 3 |
| 4 | 3 | 1 |
| 5 | 3 | 6 |
| 6 | 3 | 2 |
+--------+-------------+---------+
Now to the problem. On the front end, when I list all the announcements on a page, I would have to first query for all the announcements. Then, for each announcement, I would have to do another query for all the users that have read this announcement.
$sql = "select * from Announcements";
$result = $pdo->query($sql);
while ($row = $result->fetch())
{
$announce_id = $row['announce_id'];
$announce_msg = $row['annouce_msg'];
$readers = "";
$sql2 = "select u.user_name from Acknowledgement as a INNER JOIN User as u where announcement_id =".$annouce_id;
$result2 = $pdo->query($sql);
while ($row2 = $result2->fetch())
{
$readers .= $row2['user_name'].", ";
}
echo "id:".$annouce_id.", message:".$announce_msg.", Readers:".$readers;
}
So if there 10 announcements on the page, there will be 10 sub-queries for each announcement. What I have now does the job right now... but what if there is 1000 announcements? Then there will be 1000 sub-queries? Sounds like the database will be really hammered. So I'm hoping there is a better way of doing this.
Also, if 1000 people in the user table reads all 1000 announcements, the acknowledgement table will have 1000x1000 entries. seems like the acknowledgement table will become really really long. Will that be a problem as time goes by?
This is a really rough example of what I'm trying to do but it did take me a long time to write all this. If more details is needed let me know.
There is a better way. You can use a single query with group_concat:
select a.*, group_concat(u.user_name separator ', ') as AllUsers
from Announcements a join
Acknowledgement ak
on a.Announce_Id = ak.Announce_Id join
User u
on u.user_ID = ak.User_ID
group by a.announce_id
This uses the MySQL feature of hidden columns to group by only one column (announce_id) but still pull in a bunch of other columns with no aggregations (everything else pulled in by the "*").
If your purpose here is to filter out the announcements that your current user has read, you can do this an entirely different way. Instead of querying for every announcement, and then finding out all the users that have read those announcements and examining those results to find ones that your use has read and trimming them from the displayed list, you can just query in one go for everything a particular user (or list of users) have not yet read.
Change your query to this:
SELECT * FROM Announcements WHERE Announce_id NOT IN (SELECT ANNOUNCE_ID FROM Acknowledgement WHERE User_ID = <INSERT USER ID HERE>)
That should return all Announcement rows that this particular user has not yet acknowledged. If you change that final WHERE clause to be WHERE User_ID IN () then you can specify a list of user IDs.
EDIT: Given the comment you posted above, you could use this query to get all announcements that have been read by no one:
SELECT * FROM Announcements WHERE Announce_id NOT IN (SELECT ANNOUNCE_ID FROM Acknowledgement WHERE User_ID IN (SELECT User_ID FROM User))
The logic for putting together a query to find announcements that haven't been read by someone (if not everyone) is escaping me right this second.
EDIT THE SECOND: Every announcement, and everyone who has and has not read it, requires use of a different kind of join that you've used above, a FULL OUTER JOIN. Unfortunately MySQL doesn't have that feature IIRC, but it can be simulated with a union query
SELECT A.*, ACK.*, U.* FROM Announcements AS A
INNER JOIN Acknowledgement AS ACK ON A.Announce_ID = ACK.Announce_ID
LEFT OUTER JOIN User AS U ON ACK.User_ID = U.User_ID
WHERE U.User_ID IS NOT NULL
UNION ALL
SELECT A.*, ACK.*, U.* FROM Announcements AS A
LEFT OUTER JOIN Acknowledgement AS ACK ON A.Announce_ID = ACK.Announce_ID
RIGHT OUTER JOIN User AS U ON ACK.User_ID = U.User_ID
I think that should do it. No facilities to test at the moment, of course.
I work for a hosting company were we often get requests for installs, new domains, lag fixes etc. To get a bit of an overview of what is still open I decided to make a really simple ticket system. I have a bit of php knowledge and a bit of MySQL knowledge. For now we will be submitting the tickets ourselves based on e-mails and phonecalls from customers.
I have created the following SQL structure:
|| TICKETS || || STATUSSES || || STATUS-CODES ||
-------------- ---------------- -------------------
| ID | | ticket_id | | ID |
| cust_name | | status_id | | status_txt |
| cust_cntct | | datetime | -------------------
| subject | ----------------
| message |
--------------
I now want to make the overviw table showing all the existing tickets. A ticket is inserted with a default status. The concurring timestamp will be the time that the ticket was added. Every time a ticket moves to the next status a new status will be added with a timestamp. The newest status is always the current status.
I can't figure out how to create a query that will get every ticket with its latest status. A simple join will return a ticket as many times as the amount of statusses it has. I want to create a join but only show the results were the timestamp of the status is the newest for a certain ticket.
Try this:
SELECT a.*, b.`datettime`, d.status_txt
FROM tickets a
INNER JOIN statusses b
on a.id = b.ticket_ID
INNER JOIN
(
SELECT ticket_ID, MAX(`datetime`) CurrentTicketDate
FROM Statuses
GROUP BY ticket_ID
) c
ON b.ticket_ID = c.tecket_ID AND
b.`datetime` = c.CurrentTicketDate
INNER JOIN Status_Codes d
on b.status_ID = d.id