Schedule a snapshot of a MySQL Table - mysql

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?

Related

Client Management DB Design - Track credit based purchases

My reservation system allows us to purchase credits for clients in terms of pre defined packages. I'm struggling with how I record and calculate available credits.
Let's say we're talking about a car wash service. A client can have multiple cars and can purchase the following services, 'Wash and Wax' and 'Detailing'.
Client 1 has two cars, Car A and Car B. He brings them both in and purchases:
Car A - 1 Wash and Wax
Car A - 1 Detailing
Car B - 10 Wash and Wax
Car B - 1 Detailing
This generates 4 rows in my Purchases table, one for each service purchased.
In my DB I have two related tables tracking purchases and reservations. Table 1 Purchases, Table 2 Reservations.
In Purchases I have the following fields of note:
id
client_id
car_id
service_id
credits_purchased
credits_scheduled
credits_used
cart_id
Then in my Reservation table I have the following fields of note:
id
client_id
car_id
service_id
reservation_date
completed_datetime
car_in_datetime
car_out_datetime
purchase_id
I track the credits available by updating the Purchases table fields credits_used and credits_on_schedule as events happen.
For example, when the client makes a reservation the system adds a new record in the Reservations table, once this happens the system also runs an update query and adds +1 to the related Purchases table credits_on_schedule. When the Reservation is updated to complete the system also updates the Purchases table and adds -1 to credits_on_schedule and +1 to credits used. Simple math between credits_purchased, credits_used, and credits_on_schedule derive what credits are available for a client to use.
I feel like this isn't a good way to track the credits. My question is what is a better implementation? Should I just track credits_purchased then use count queries on the Reservation table to calculate credits_used and credits_on_schedule? Should I be using a pivot table to track? I can't seem to wrap my head around what is the cleanest design.
It looks to me that the design is ok in general.
A reservation can only have one purchased related to it so purchase_id field is a foreign key in Reservation table.
Nevertheless, my advise to you is to create a log system of all these record updates.
As you mentioned, as events are fired the system updates the calculated fields.
What if for some reason the system fails at a certain point? You should be able to track these events.
One way to avoid this is, as you mentioned, calculate credit_used by a count query on all completed reservations.

Relational Database Logic

I'm fairly new to php / mysql programming and I'm having a hard time figuring out the logic for a relational database that I'm trying to build. Here's the problem:
I have different leaders who will be in charge of a store anytime between 9am and 9pm.
A customer who has visited the store can rate their experience on a scale of 1 to 5.
I'm building a site that will allow me to store the shifts that a leader worked as seen below.
When I hit submit, the site would take the data leaderName:"George", shiftTimeArray: 11am, 1pm, 6pm (from the example in the picture) and the shiftDate and send them to an SQL database.
Later, I want to be able to get the average score for a person by sending a query to mysql, retrieving all of the scores that that leader received and averaging them together. I know the code to build the forms and to perform the search. However, I'm having a hard time coming up with the logic for the tables that will relate the data. Currently, I have a mysql table called responses that contains the following fields,
leader_id
shift_date // contains the date that the leader worked
shift_time // contains the time that the leader worked
visit_date // contains the date that the survey/score was given
visit_time // contains the time that the survey/score was given
score // contains the actual score of the survey (1-5)
I enter the shifts that the leader works at the beginning of the week and then enter the survey scores in as they come in during the week.
So Here's the Question: What mysql tables and fields should I create to relate this data so that I can query a leader's name and get the average score from all of their surveys?
You want tables like:
Leader (leader_id, name, etc)
Shift (leader_id, shift_date, shift_time)
SurveyResult (visit_date, visit_time, score)
Note: omitted the surrogate primary keys for Shift and SurveyResult that I would probably include.
To query you join shifts and surveys group on leader and taking the average then jon that back to leader for a name.
The query might be something like (but I haven;t actually built it in MySQL to verify syntax)
SELECT name
,AverageScore
FROM Leader a
INNER JOIN (
SELECT leader_id
, AVG(score) AverageScore
FROM Shift
INNER JOIN
SurveyResult ON shift_date = visit_date
AND shift_time = visit_time --depends on how you are recording time what this really needs to be
GROUP BY leader ID
) b ON a.leader_id = b.leader_id
I would do the following structure:
leaders
id
name
leaders_timetabke (can be multiple per leader)
id,
leader_id
shift_datetime (I assume it stores date and hour here, minutes and seconds are always 0
survey_scores
id,
visit_datetime
score
SELECT l.id, l.name, AVG(s.score) FROM leaders l
INNER JOIN leaders_timetable lt ON lt.leader_id = l.id
INNER JOIN survey_scores s ON lt.shift_datetime=DATE_FORMAT('Y-m-d H:00:00', s.visit_datetime)
GROUP BY l.id
DATE_FORMAT here helps to cut hours and minutes from visit_datetime so that it could be matched against shift_datetime. This is MYSQL function, so if you use something else you'll need to use different function
Say you have a 'leader' who has 5 survey rows with scores 1, 2, 3, 4 and 5.
if you select all surveys from this leader, sum the survey scores and divide them by 5 (the total amount of surveys that this leader has). You will have the average, in this case 3.
(1 + 2 + 3 + 4 + 5) / 5 = 3
You wouldn't need to create any more tables or fields, you have what you need.

Get maximum number of consecutive duplicate records in mysql

Suppose there are 25 groups of programmers, with 5-100 programmers in each group. Each group of programmers is tasked with writing the query that this question refers to. In response to this task, many programmers in each group begins drinking heavily. Each group has a stocked bar consisting of:
Whiskey
Vodka
Beer
Water
Every time a programmer finishes a drink, a new row is added to the table including:
Time the drink was finished
Group ID
Programmer ID
Type of drink consumed
The program manager wants to be emailed every six hours with a list of programmers who have consumed 5 or more Beers in a row, within the last 6 hours, without having a shot of vodka/whiskey, or a glass of water. The total number of beers that each programmer has consumed without switching to another drink at least once needs to be included in the report.
If at least one drink other than a beer is consumed before reaching 5 beers, then that programmer will not go on the list.
There are no upper or lower bounds on the number of drinks that a programmer can consume in a 6-hour period.
There are no requirements on the type or order of drinks that any programmer can consume.
The MySQL database has a table 'drinks' with:
drinks_id INT(11) PK NN AI
group_id INT(11) NN
programmer_id INT(11) NN
type_of_drink VARCHAR(25) NN
time_finished DATETIME NN
(type of drink should probably be in another table and the drink_type_id used, but I'm going for simplicity here)
The core of what I'm looking for is the maximum count value of the number of consecutive rows with type_of_drink = 'beer' for every group/programmer combination during a specified period of time. I've exhausted my sql skills trying to count the number of consecutive records which exist between two records with type_of_drink <> 'beer' and returning the maximum value for each group/programmer combination. I can't seem to get it right, and that may not be the way to look at this problem in the first place.
Thanks in advance. I'll be happy to provide any additional information or requirements if needed.
SELECT DISTINCT programmer_id
FROM (
SELECT
programmer_id,
#beercounter := IF(#prev_programmer != programmer_id OR type_of_drink != 'beer', 1, #beercounter + 1) AS how_many_beer_in_a_row,
#prev_programmer := programmer_id
FROM
your_table y
, (SELECT #beercounter:=1, #prev_programmer:=NULL) vars
WHERE time_finished >= NOW() - INTERVAL 6 HOUR
ORDER BY programmer_id, time_finished
) sq
WHERE how_many_beer_in_a_row >= 5

"Sparse" Rank in Business Objects XI Web Intelligence?

In Business Objects XI Web Intelligence the Rank function returns dense results. For example when ranking by "Amount" I want to return the top ten records only. However three records tie for 5th place on "Amount". Result is a total of 12 records: one each for places 1 to 4 and 6 to 10 and 3 records for 5th place.
Desired result is a "sparse" top ten that drops the two lowest ranked records (places 9 and 10).
I tried to do this and rank customers by amount.
I have 2 objects: [Amount] and [Customernumber].
[Customernumber] is numeric.
I created a new variable:
[varForSorting]=[Amount]*10000000+ToNumber([Customernumber])
Then I rank by the new variable [varForSorting].
Customers with the same Amount will be sorted in Alphabetic order by Customer number. I hope this helps.
Here is an example of how I solved it for a change in Account Count over time. This approach allows you to break your dense rank ties using other measures in your data provider. Basically you use multiple measures in one rank and decide which measure to rank by first, second, etc:
Step 1: Determine the change amount
v_Account_Count_Delta_Amount
=([v_Account_Count_After] - [v_Account_Count_Before])
Step 2: Rank the change amounts (this is where ties and dense rank cause multiple rows to be returned)
v_Account_Count_Delta_Amount_Rank
=NoFilter(Rank([v_Account_Count_Delta_Amount]))
Step 3: Compute the tie breaking rank using other measures
v_MonthToDateMeasuresRank
=NoFilter(Rank([Month To Date Sva]+ [Bank Share Balance] + [Total Commitment]))
Step 4: Compute a combined rank that is now free from ties and weight your ranks however you choose
v_Account_Count_Combined_Rank
=Rank([v_Account_Count_Delta_Amount_Rank]* 1000000 + [v_MonthToDateMeasuresRank];Bottom)
Step 5: Filter your data block for v_Account_Count_Combined_Rank <= 10
Ultimately depending on your data it could still result in a tie unless you take the additional step of ranking by some other unique attribute that you can turn to a number (see Maria Ruchko's answer for that bit of magic using Customer Number). I tried to do that with RowIndex() and LineNumber() but could not get usable results. My measures when added together happen to never tie so this works for my specific data blob.

MySQL get only the row with the highest ID of a query

Hello Stackoverflow community,
This is my first post here, so I apologize for my bad English! :)
If you don't want to read everything, the Questions are marked like this.
The title is a little misleading, but I didn't know how to explain it in a better way, but the detailed explanation should let you understand:
I have a big log table (about 500000 rows at this time), where a game server logs many actions that occur in the game. I want to extract some specific log rows the most efficient way.
I can't change the logging system of the game server, if I could I would change it to many more log tables, to create more compact logs. (because executing queries on that table takes it's time..)
Now my problem is, that I want to get the last log row of a specific type and from a specific player id to get the players last action, and I don't know how to do that in an efficient way.
Example:
SELECT * FROM log WHERE logType = "PLAYER" AND playerID = [playerID] ORDER BY time DESC LIMIT 1
Then the output on the website would be:
You last action was [the human readable action and additional information].
MySQL profiling now tells me that sorting of the results takes the most amount of time.
Now my question is: Is it possible to get only the last row of a specific player id and type?
I guess it could be done with the ID, cause it has auto_increment. So is it possible to get the row with the highest ID, a specific type and a specific player id?
The table structure:
ID(int) | logType(varchar) | time(datetime) | playerID(int) | positionX(int) | positionY(int) | actionID(int) | action(varchar) | hints(varchar) | ip(varchar) | itemNumber(int)
Explaination:
ID: the unique id of the logged action
logType: the type of the logged action (Example: "PLAYER" or "ITEM")
time: the time the action occured
playerID: the id of the player (or other id's related to that type)
positionX: X position in the game
positionY: Y position in the game
actionID: an id in relation to the action (Example: If the log action is "KILLED_BY_PLAYER", then the player id of the other player who killed the player)
action: the action that is logged (Example: KILLED_BY_PLAYER)
hints: Some useful hints like the name of the player
ip: The IP of the player
itemNumber: The number of the Item, if an Item is involved, else NULL
Thanks for your help. :)
to get the highest id:
select max(id) from table;
the others you could put a where clause in the select statement.
You should be able to use your query where you sort on time with LIMIT 1. If your sort on the column time is slow, you must make sure the indexes are optimized (run explain on your query). You will need indexes on both logtype, player_id and time. Even with 500 000 rows this shouldn't be a problem...