Database design for Group Notification System - mysql

I am trying to create a group notification system. If I am in a group, then anyone who comment on the group's wall, a notification will send out to every group member. Here is my database design: I have two tables: Notification and NotificationRead.
NotificationRead
+userId (String)
+lastRead (int) - default is 0
Notification
...
+time(int)
...
Every user has one entry in NotificationRead, it keep track of when is the last time I read my notification.
The logic is: for a particular user, if Notification.time > NotificationRead.lastRead, then that notification is considered unread. Let say that in group A, there are 4 notifications I have not read, and their time is 7, 8, 9, 10, then when I click onto group A, I set my NotificationRead.lastRead = 10 (the largest time), so I wont read them again. New notifications will have their time start at 11. Now, here is my problem. Let say I have 3 groups, A, B and C
A (4): largest time is 10
B (1): largest time is 14
C (1): largest time is 12
if I click onto A, my NotificationRead.lastRead = 10, the 4 next to A clear off, 1 next to B and C stay put. Now if I click on B, my lastRead now is 14, so not only it clear off the 1 next to B but also the 1 next to C since 14 > 12. Can anyone help me think of a way to solve this. I am open to completely redesign everything

Cant you just add a groupID column to your NotificationRead table so you know the lastRead value for each User\Group combination>?

If you wish to know the last notification time per user per group, you must store that information. Therefore, each user must have more than one record in NotificationRead, which must become a separate table from the user table. This table will have three columns, the user_id, the group_id, and the lastread value for that user/group.

Related

How to select two MySQL rows and then compare a column and return an output

I've a table with a structure something like this,
Device | paid | time
abc 1 2 days ago
abc 0 1 day ago
abc 0 5 mins ago
Is it possible to write a query that checks the paid column on all the rows where Device = abc and then outputs the most recent two rows that different. Basically, something like an if statement saying if row 1 = 1 and row 2 = 0 output that but only if it's the most recent two columns that are different. For example, in this case, the first and second row. The table is being updated whenever a user changes from a free to paid account etc. It is also updated in different columns for different reasons hence the duplicate 0s for example.
I know this would probably be done better by having another table altogether and updating that every time the user switches account type, but is there any way to make this work?
Thanks
Example:
http://rextester.com/MABU7860 need further testing on edge cases but this seems to work.
SELECT A.*, B.*
FROM SQLfoo A
INNER JOIN SQLFoo B
on A.Device = B.Device
and A.mTime < B.mTime
WHERE A.Paid <> B.Paid
and A.device = 'abc'
ORDER BY B.mTime Desc, A.MTime Desc
LIMIT 1
By performing a self join we on the devices where the time from one table is less than the time from the next table (thus the two records will never matach and we only get the reuslts one way) and we order by those times descending, the highest times appear first in the result since we limit by a single device we don't need to concern ourselves with the devices. We then just need compare the paid from one source to the paid in the 2nd source and return the first result encountered thus limit 1.
Or using user variables
http://rextester.com/TWVEVX7830
in other engines one might accomplish this task by performing the join as in above, assigning a row number partitioned by the device and then simply return all those row_numbers with a value of 1; which would be the earliest date discrepency.
Use LIMIT to limit the number of record on mysql:
http://www.mysqltutorial.org/mysql-limit.aspx
In your case, use LIMIT 2
and then put the 2 record that you just select into an array, then compare the array if the value is different. If they are different then print

Summing Columns up with some exceptions

I am working on a database with two different tables.
The first contains every change in the database like a transaction table. It contains the object that was bought/sold, how many of them where bought/sold, when this tranaction happend and in which place.
The second table contains the total value of every object that should be available in those places.
Now here is my question:
I want to automaticly sum up every entry with the same object and location inside of table one and save this value inside of table two.
BUT
Sometimes there are special entrys in table one which should not be summed up with the other values. They should overwrite the value.
I have an example of how this summing up should look like:
n = normal value, s = special value
n: 1 sum: 1
n: 2 sum: 3
s: 7 sum: 7
n: 5 sum: 12
n: 4 sum: 16
n: 7 sum: 23
s: 20 sum: 20
To help you help me I have some additional informations:
There are 4 columns inside of table one
The first one is called object and contains the object number for which this entry takes effect.
The second column contains the amount of that object. Whether it was bought or sold.
The third column tells me on which locations this transaction belongs to. Which also means that every object has different amounts depending on the location.
The fourth column contains an information why this transaction happend. It tells me if this transaction happend because I bought something or because I sold something OR because I counted my stock.
This is the special indicator which should tell my database not to sum up this value but instead overwrite the previous one with this.
The fifth and last column contains the date when this transaction happend. This is very important because the whole table is sorted by the date. And it tells when those special values come in place.
The other table just contains the summed up value for every object in every location.
This below will return the sum of each record for a particular Object 'MyObj' starting from the last instance of a 'Special' entry (inclusive).
(Untested)
SELECT Sum(a.Amount) AS TheSum
FROM tblMyTable a
WHERE ID_PK> = nz((
SELECT max(ID_PK)
FROM tblMyTable
WHERE Object=a.Object AND IsSpecial=1
),0)
AND a.Object='MyObj'

Sql query to keep "counted" the rows that have been deleted

I have a classified site... I'm trying to make a sql query that COUNTS the number of ads the user has posted in last 7 days, but I have a problem...
I'm trying to show in user profile something like this for example: [Username] has posted 30 ads in last 7 days
Here is my sql query ->
SELECT COUNT(*)
FROM table_name
WHERE user_id = '[user_id]' AND created_date > NOW() - INTERVAL 7 DAY
So in my case "table_name" contains ALL the ads from all the users and by "user_id = '[user_id]'" I show the user A his number of ads, and to USER B his number of ads etc...
So this query works, it counts the number of ads correctly, BUT, if for example user enters on site and DELETE's 1,2 or whatever number of his ads, this number will be "minused" from the "[Username] has posted 30 ads in last 7 days"
So let's say for example user posted 20 ads in the last 5 days - The correct result is [Username] has posted 20 ads in last 7 days
Now user enters on site and delete's 4 ads - Now the result is [Username] has posted 16 ads in last 7 days
Can somebody help me please, what can I add to the query so the count still shows the correct number of ads (in my case 20 ads), even if the ads where deleted..
Thank you
Cheers
Instead of deleting a row using a DELETE ... WHERE ... statement, add a deleted column and use an UPDATE statement:
UPDATE ... SET deleted = 1 WHERE ...
Then your counting function will work without modification.
Of course you will now have to fix all the rest of your code to not show deleted adverts. You can do this by adding WHERE NOT deleted to all your other queries. You could also create a view that only shows ads that are not deleted and update your code to query this view instead of the original table.
Rather than deleting the ads from the system, add a "deleted" flag, or move them to a deleted table. This way you never lose the record of them.
There's nothing you can add to a query to find data which has been deleted. You need not to delete the data, but add a marker to the record the user wants to delete to indicate that it's been removed from display.
As well as allowing the record to be counted, it has the additional advantage that the user can be permitted to reinstate that advert, if he wants to.

Schedule a snapshot of a MySQL Table

It is possible to schedule a snapshot of a MySQL table?
The situation:
I have a table that collects votes (up and down) from a website. It registers the number of votes (that can be either a vote up, “+1”, or a vote down, “-1”), and records the score (for example, if one ID received 5 votes, 3 voting "up" (+1) and 2 voting "down" (-1), then the table would record that number of votes was "5", and that the vote score was "2". It is recorded in a table that has the following column headers/fields:
ID | Score | nvotes
…where ID is the reference of the item being voted on; 'score' is the actual score that is calculated (from the number of “+1” and “-1” votes), and 'nvotes' is the number of votes that have been received
This is great for looking at the website at any point in time and seeing what the score is, and how many people have voted.
However, I now want to be able to chart the trend for the ID – to look back over time and see how the score has gone up and down over time.
Is there a facility in MySQL to be able to take a snapshot at the end of each day, recording where that particular ID was at the end of that day in terms of their score and the number of votes received, and store this in another table so that I can create charts and analysis over time?
Or, failing that, can anyone think of a better, more intelligent way of trying to acheive what I need?

Count a specific value from multiple columns and group by values in another column... in mysql

Hey. I have 160 columns that are filled with data when a user fills a report form out and submit it. A few of these sets of columns contain similar data, but there needs to be multiple instance of this data per record set as it may be different per instance in the report.
For example, an employee opens a case by a certain type at one point in the day, then at another point in the day they open another case of a different type. I want to create totals per user based on the values in these columns. There is one column set that I want to target right now, case type. I would like to be able to see all instances of the value "TSTO" in columns CT1, CT2, CT3... through CT20. Then have that sorted by the employee ID number, which is just one column in the table.
Any ideas? I am struggling with this one.
So far I have SELECT CT1, CT2, CT3, CT4, CT5, CT6, CT7, CT8, CT9, CT10, CT11, CT12, CT13, CT14, CT15, CT16, CT17, CT18, CT19, CT20 FROM REPORTS GROUP BY OFFICER
This will display the values of all the case type entries in a record set but I need to count them, I tried to use,
SELECT CT1, CT2, CT3, CT4, CT5, CT6, CT7, CT8, CT9, CT10, CT11, CT12, CT13, CT14, CT15, CT16, CT17, CT18, CT19, CT20 FROM REPORTS COUNT(TSTO) GROUP BY OFFICER
but it just spits an error. I am fairly new to mysql databasing and php, I feel I have a good grasp but query'ing the database and the syntax involved is a tad bit confused and/or overwhelming right now. Just gotta learn the language. I will keep looking and I have found some similar things on here but I don't understand what I am looking at (completely) and I would like to shy away from using code that "works" but I don't understand fully.
Thank you very much :)
Edit -
So this database is an activity report server for the days work for the employees. The person will often open cases during the day. These cases vary in type, and their different types are designated by a four letter convention. So your different case types could be TSTO, DOME, ASBA, etc etc. So the user will fill out their form throughout the day then submit it down to the database. That's all fine :) Now I am trying to build a page which will query the database by user request for statistics of a user's activities. So right now I am trying to generate statistics. Specifically, I want to be able to generate the statistic of, and in human terms, "HOW MANY OCCURENCES OF "USER INPUTTED CASE TYPE" ARE THERE FOR EMPLOYEEIDXXX"
So when a user submits a form they will type in this four letter case type up to 20 times in one form, there is 20 fields for this case type entry, thus there is 20 columns. So these 20 columns for case type will be in one record set, one record set is generated per report. Another column that is generated is the employeeid column, which basically identifies who generated the record set through their form.
So I would like to be able to query all 20 columns of case type, across all record sets, for a defined type of case (TSTO, DOME, ASBA, etc etc) and then group that to corresponding user(s).
So the output would look something like,
316 TSTO's for employeeid108
I hope this helps to clear it up a bit. Again I am fairly fresh to all of this so I am not the best with the vernacular and best practices etc etc...
Thanks so much :)
Edit 2 -
So to further elaborate on what I have going on, I have an HTML form that has 164 fields. Each of these fields ultimately puts a value into a column in a single record set in my DB, each submission. I couldn't post images or more than two URLs so I will try to explain it the best I can without screenshots.
So what happens is this information gets in the DB. Then there is the query'ing. I have a search page which uses an HTML form to select the type of information to be searched for. It then displays a synopsis of each report that matches the query. The user than enters the REPORT ID # for the report they want to view in full into another small form (an input field with a submit button) which brings them to a page with the full report displayed when they click submit.
So right now I am trying to do totals and realizing my DB will be needing some work and tweaking to make it easier to create querys for it for different information needed. I've gleaned some good information so far and will continue to try and provide concise information about my setup as best I can.
Thanks.
Edit 3 -
Maybe you can go to my photobucket and check them out, should let me do one link, there is five screenshots, you can kind of see better what I have happening there.
http://s1082.photobucket.com/albums/j376/hughessa
:)
The query you are looking for would be very long and complicated for your current db schema.
Every table like (some_id, column1, column2, column3, column4... ) where columns store the same type of data can be also represented by a table (some_id, column_number, column_value ) where instead of 1 row with values for 20 columns you have 20 rows.
So your table should rather look like:
officer ct_number ct_value
1 CT1 TSTO
1 CT2 DOME
1 CT3 TSTO
1 CT4 ASBA
(...)
2 CT1 DOME
2 CT2 TSTO
For a table like this if you wanted to find how many occurences of different ct_values are there for officer 1 you would use a simple query:
SELECT officer, ct_value, count(ct_value) AS ct_count
FROM reports WHERE officer=1 GROUP BY ct_value
giving results
officer ct_value ct_count
1 TSTO 2
1 DOME 1
1 ASBA 1
If you wanted to find out how many TSTO's are there for different officers you would use:
SELECT officer, ct_value, count( officer ) as ct_count FROM reports
WHERE ct_value='TSTO' GROUP BY officer
giving results
officer ct_value ct_count
1 TSTO 2
2 TSTO 1
Also any type of query for your old schema can be easily converted to new schema.
However if you need store additional information about every particular report I suggest having two tables:
Submissions
submission_id report_id ct_number ct_value
primary key
auto-increment
------------------------------------------------
1 1 CT1 TSTO
2 1 CT2 DOME
3 1 CT3 TSTO
4 1 CT4 ASBA
5 2 CT1 DOME
6 2 CT2 TSTO
with report_id pointing to a record in another table with as many columns as you need for additional data:
Reports
report_id officer date some_other_data
primary key
auto-increment
--------------------------------------------------------------------
1 1 2011-04-29 11:28:15 Everything went ok
2 2 2011-04-29 14:01:00 There were troubles
Example:
How many TSTO's are there for different officers:
SELECT r.officer, s.ct_value, count( officer ) as ct_count
FROM submissions s JOIN reports r ON s.report_id = r.report_id
WHERE s.ct_value='TSTO'
GROUP BY r.officer