Arma 2 DayZ Epoch SQL dead body cleaner - mysql

I have been trying to figure out a way to do something like what this Delete all records except the most recent one?
But I have been unable to apply it to my circumstance.
My circumstance:
https://gyazo.com/178b2493e42aa4ec4e1a9ce0cbdb95d3
SELECT * FROM dayz_epoch.character_data;
CharacterID, PlayerUID, InstanceID, Datestamp, LastLogin, Alive, Generation
5 |76561198068668633|11|2016-05-31 18:21:37|2016-06-01 15:58:03|0|1
6 |76561198068668633|11|2016-06-01 15:58:20|2016-10-08 21:30:36|0|2
7 |76561198068668633|11|2016-10-08 21:30:52|2016-10-09 18:59:07|1|3
9 |76561198010759031|11|2016-10-08 21:48:32|2016-10-08 21:53:31|0|2
10|76561198010759031|11|2016-10-08 21:53:55|2016-10-09 19:07:28|1|3
(Look at image above) So I am currently trying to make a better method for deleting dead bodies from my database for my DayZ Epoch server. I need a code to delete Where ALIVE = 0 if that same PlayerUID has another instance where it is ALIVE = 1.
The other thing the code could do is just delete all players except the most recent one for each PlayerUID. I hope this makes sense. It's hard to explain. The first link explains better for me.
But basically, I want to delete any dead player that now has an alive player with that same PlayerUID. If I were better at coding, I could see many variables I could use like PlayerUID (a must), Datestamp, Alive, and generation. Probably only need 2 of those, one being the PlayerUID.
Thanks a bunch.
The easiest to me seems like it would be something like: SORT by PlayerUID AND FOR EACH PlayerUID DELETE ALL EXCEPT(?) newest Datestamp.
This would keep the player stats from their dead body in case they do not create a new character before this script is called.

So basicly, you need to be sure that on a Insert (or update of ALIVE to 1) of a player, you removed all previous (just in case, normaly there should be only one) player with the same PlayerUID as the new one.
The easiest is to create a trigger that will run before the insert (and on UPDATE if this is possible to update ALIVE to 1 to revieve one). Using the UID of the new player to run a delete on the table for the specific UID. This is that simple ;)
For the trigger, this should look like this
Create trigger CLEAR_PLAYER
before insert on dayz_epoch.character_data
For Each Row
Delete from dayz_epoch.character_data
where PlayerUID = NEW.PlayerUID
and Alive = 0 --Just in case, but what will happen if there where a line with Alive = 1 ?
This will be executed before the insert in the table dayz_epoch.character_data
(so don't remove the new one). This will remove every line with the PlayerUID of the inserted line. If you want to add some security, you could add the and Alive= 0 in the condition.
Edit :
Didn't write trigger in a long time, but I use the official doc as a reminder. Take a look if you need.

Related

FDQuery Interface to Progress Bar - DELPHI

I am trying to make an interface for my insert Query, this moves a huge number of data.
DataModule2.FDQueryInsertExceed.Close;
DataModule2.FDQueryInsertExceed.Sql.Clear;
DataModule2.FDQueryInsertExceed.Sql.Add('INSERT IGNORE INTO tblLogs');
DataModule2.FDQueryInsertExceed.Sql.Add('SELECT * FROM tbllogs WHERE Datetimelog <
date_sub(NOW(), INTERVAL 1 month);');
DataModule2.FDQueryInsertExceed.ExecSQL;
Dont know where to put the progress bar, and also if you can post here a link with full manual of FD Components.
FireDAC includes the TFDEventAlerter, which allows applications to receive certain notifications
from the SQL backend, including some progress notifications. Unfortunately, it does not support
MySQL so you are going to have to devise a way of updating your ProgressBar yourself.
The main problem with doing it yourself is that after you call DataModule2.FDQueryInsertExceed.ExecSQL,
it will not return until ExecSQL has completed execution, so you can't get any opportunity
to update your ProgressBar until then and by the time that you do, the SQL backend has finished
working.
So, realistically, the best you can do is to snip your db inserted up into a series of batches and
update the ProgressBar after each one. Before you start the batches, you can do a SELECT COUNT(*)
which should tell you at least approximately how many rows will be involved overall, so that
you can calculate the percentage complete after each batch. I say "approximately"
in case new inserts are required while your ExecSQL is executing,
The simplest place to start is by determining how many of your inserts can be executed in
a few hundred milliseconds, parameterize your SQL to match that and use a TTimer to start
each batch. So your TTimers's OnTimeer wou look something like
TForm1.OnTimer1.OnTimer(Sender : TObject);
var
S : String;
begin
S := 'INSERT IGNORE INTO tblLogs SELECT * FROM tbllogs WHERE Datetimelog ... //
// complete as necessary to add a starting DateTime and an ending one for the batch
DataModule2.FDQueryInsertExceed.Sql.Text := S;
DataModule2.FDQueryInsertExceed.ExecSQL;
// Update ProgressBar here
end;
An enhancement (but a step change in difficulty) would be to call DataModule2.FDQueryInsertExceed.ExecSQL
in a background thread and, once it has executed, execute code in the main, VCL thread, not in the background thread, to update
the ProgressBar. However, exactly how to do that is way beyond the scope of this answer.

select from table where two parameters satisfy in mysql

I am totally clueless how to get around to get the following kinda result from the same table in MySQL.
Required Result:
The raw data as shown in below image.
Mc_id and op_id can be different. For example, if mc_id is 4 and op_id is 10 then it has to loop through each vouid and extract done_on_date, again it has to loop through for the same mc_id 4 and op_id 10 and extract done_on_date where done_on_date is after first extracted done_on_date. Here second extracted done_on_date, we refer to, as next_done_on_date, just to distinguish it differently. Accordingly continue till end of the table. I hope I am clear enough now.
The idea is basically to see when was particular operation_id carried out for the said machine having mc_id. First time operation done is refered to as done_on_date and when the same operation carried out for the same machine next time, we refer to as next_done_on_date but actually inside the database table it is done_on_date.
Though let me know if anything yet to be clarified

Duplicate row and everything related to that ID in different tables

I'm working on a software for managing the Rally company of my boss, where he can manage all the volunteers, their affectations, and many other things.
But the volunteers and these others things vary depending on the event, so they all have a column representing the event that they are linked/related to.
My boss requested that I add a "duplicate" button, that would duplicate an event (from my events table) and also duplicate all the volunteers, and values from any other table that is linked to that event, so the new duplications are linked to the new event.
The reason for this, is that he is constantly organizing rallies, and often it happens that the data from a Rally (event) to another is almost the same, so instead of adding it all manually, he'd rather make an entire duplication of the event and all the data related to it, then manually add and remove the errors in it.
I would like to know, is there any way in MySQL that I could duplicate an event, and everything that is linked to it's ID, even though they are in different tables, and make the duplications have the ID of the new event?
Sadly I don't have very much time, but until I get an answer I can work on other tasks my boss gave me.
Thank you so much to anybody who helps me or gives me any hint!!
EDIT:
Here's the schema of my Database (I know it's kinda dirty and there's issues with it, my boss gave me indications on how to create the database since he used to work in the domain before, but he didn't tell me how to make the links and he wants to make them himself)
And I apologize for the French language and the weird names..
Basically I wish to duplicate an entry in the "event" table, all the "affect" and "lieu" entries that are linked to it, and all the "tache" entries related the the duplicated "lieu" entries.
EDIT 2:
Thank you MrMadsen for the Query!
I had to fix it a bit, but here's what it looks like after.
SET #NEWEVEN = (SELECT MAX(NO_EVE) from db_rallye.event)+1;
INSERT INTO db_rallye.event
SELECT #NEWEVEN,
NM_EVE,
AN_EVE,
DT_EVE,
NM_REG_EVE
FROM event
WHERE NO_EVE = event_to_duplicate;
SET #NO_AFFECT_LIEU = (SELECT MAX(NO_AFF) from db_rallye.affect);
INSERT INTO db_rallye.affect
SELECT #NO_AFFECT_LIEU:=#NO_AFFECT_LIEU+1,
CO_AFF,
DT_AVI_AFF,
DS_STA_AFF,
CO_STA_AFF,
NO_BRA_EVN,
NO_PERS,
#NEWEVEN,
NO_EQU,
NO_LIE,
NO_PERS_RES,
IN_LUN,
IN_BAN,
DS_HEB,
IN_HEB_JEU,
IN_HEB_VEN,
IN_HEB_SAM,
NO_BOR,
NO_TUL_CAH,
NB_SPEC
FROM affect
WHERE NO_EVEN = event_to_duplicate;
INSERT INTO db_rallye.lieu
SELECT NO_LIE,
#NEWEVEN,
CO_LAT,
CO_LON,
FI_IMA,
FI_CRO,
FI_TUL,
DS_LIE,
DS_COU,
DS_LON,
NB_BLK,
VL_KM,
IN_FUS,
VL_DIS_FUS,
NO_LIE_FUS_SUI
FROM lieu
WHERE NO_EVEN = event_to_duplicate;
SET #NO_AFFECT_TACHE = (SELECT MAX(NO_TAC) from db_rallye.tache);
INSERT INTO db_rallye.tache
SELECT #NO_AFFECT_TACHE:=#NO_AFFECT_TACHE+1,
NO_LIE,
#NEWEVEN,
NO_AFF,
DS_REP,
DS_TAC
FROM tache
WHERE NO_LIE IN
(SELECT NO_LIE FROM lieu WHERE NO_EVEN = event_to_duplicate);
If a lot of the events contain similar information than I would create a template (or templates and the ability to create/modify templates) containing all of the information that you would duplicate.
Then when a new event is created he can just choose a starting template and then only add whatever data is unique to that event. In my opinion this would be much better than constantly duplicating the data.
As far as how to duplicate a row and all the associated rows, this is completely dependent on your database schema and how the tables relate to one another. If you post the relevant part of that we can help you more.
Edit
Here are the queries I came up with, test them in a dev database first but I think they will work. Let me know. Good luck!
INSERT INTO `event`
SELECT NULL NO_EVE,
NM_EVE,
AN_EVE,
DT_EVE,
NM_REG_EVE
FROM `email_log`
WHERE id NO_EVE = id_of_event_to_duplicate
INSERT INTO `affect`
SELECT NULL NO_AFF,
CO_AFF,
DT_AVI_AFF,
DS_STA_AFF,
CO_STA_AFF,
NO_BRA_EVN,
NO_PERS,
NO_EVEN,
NO_EQU,
NO_LIE,
NO_PERS_RES,
IN_LUN,
IN_BAN,
DS_HEB_JEU,
IN_HEB_VEN,
IN_HEB_SAM,
NO_BOR,
NO_TUL_CAH,
NB_SPEC
FROM `affect`
WHERE NO_EVE = id_of_event_to_duplicate
INSERT INTO `lieu`
SELECT NULL NO_LIE,
NO_EVEN,
CO_LAT,
CO_LON,
FI_IMA,
FI_CRO,
FI_TUL,
DS_LIE,
DS_COU,
DS_LON,
DB_BLK,
VL_KM,
IN_FUS,
VL_DIS_FUS,
NO_LIE_FUS_SUI
FROM `lieu`
WHERE NO_EVEN = id_of_event_to_duplicate
INSERT INTO `tache`
SELECT NULL NO_TAC,
NO_LIE,
NO_EVEN,
NO_AFF,
DS_REP,
DS_TAC
FROM `tache`
WHERE NO_LIE IN
(SELECT NO_LIE FROM `lieu` WHERE NO_EVEN = id_of_event_to_duplicate)

MySql: How to delete the delay between SELECT and UPDATE

I have a simple set up for assigning opponents in a game.
Basically if the matchID is zero(value comes from elsewhere), a new match needs to be created, and it will perform a mysql select on the last matchID record to ascertain if there is someone waiting for a match or not.
To see if a player is waiting we can see if the teamB space is Zero (not taken). If however teamB has a value then no one is waiting and a new match must be created with this player as a 'team A'.
The code is as follows:
if ($matchID == 0)
{
$teamBquery = $conn ->query("SELECT matchID,teamBID,teamAID FROM challengeMatches ORDER BY matchID DESC LIMIT 1 ");
$teamBarray = $teamBquery->fetch(PDO::FETCH_ASSOC);
$teamBID=$teamBarray[teamBID];
$matchID=$teamBarray[matchID];
$teamAID=$teamBarray[teamAID];
if ($teamBID == 0){
$newChallenge = $conn ->query ("UPDATE challengeMatches SET managerBID='$managerID', teamBID='$teamID',matchStatus=1 WHERE matchID='$matchID'");
}else{
$filler = 0;
$matchID = $matchID+1;
$newChallenge = $conn ->query ("INSERT INTO challengeMatches (matchID,managerAID,managerBID,matchStatus,teamAID,teamBID) VALUES ('','$managerID','$filler','$filler','$teamID','$filler')");
}
}
My concern as someone pretty inexperienced is that as far as I can see there will be a delay between selecting the info and updating the info and so technically two mysql selects might return the same matchID to be used. And then even using the matchID+1 as variable is risky because it could be out of sync with the auto-increment matchID that is created in the database.
Are my fears founded or is the code so fast that the probability is not worth worrying about?
If i should be worried what can I do?
You firstly need to identify if you really need a solution to overcome this, the time gap should be so small unless you run a massive site the likelihood of selecting two matchId's is remote.
However there are really three area's you can look to improve this:
Locking - look at SELECT .. FOR UPDATE or SELECT ... LOCK IN SHARE MODE
Transactions
Refactor the database to actually update with a limit first and then select the updated range

Using logic within an update and returning updated fields using as few queries as possible

I'm writing a video game in javascript on a server that saves info in a mysql database and I am trying to make my first effect attached to simple healing potion item. To implement the effect I call a spells table using spell_id and it gets a field called effect containing the code to execute on my server. I use the eval() function to execute the code in the string. In order to optimize the game I want to run as few queries as possible. For this instance (and I think the answer will help me evaluate other similar effects) I want to update the 'player' table which contains a stat column like 'health' then I want it to add n which will be a decreasing number 15 then 250 ms later add 14 then 13 until that n=1 the net effect is a large jump in health then smaller and smaller accomplishing this is relatively easy if the player's health reaches his maximum allowed limit the effect will stop immediately...
but I'd like to do a single update statement for each increase rather than a select and an update every 250ms to check if health > max_health and make sure the player's health doesn't go above his max health. So to digress a bit I'd like a single update that given this data
player_id health max_health
========= ====== ==========
1 90 100
will add 15 to health unless (max_health-health) < 15... in this case it should only add 10.
An easier solution might be
if I could just return health and max health after each update I update it I don't mind doing a final
pseudo code
if health > max_health
update health set health = max health
So if anyone could explain how to return fields after an update that would help.
Or if anyone could show how to use logic within the update that would also help.
Also, If I didn't give enough information I'm sorry I'd be glad to provide more I just didn't want to make the question hard to understand.
update health
set health = least(max_health, health +<potion effect>)
where player_id = ...
EDIT
For your other question : normally, i think that update returns the number of affected rows. So if you try to update health when health is already = max_health, it should return 0.
I'd know how to do this in php, for example, but just said you where using javascript... so ?
http://dev.mysql.com/doc/refman/5.6/en/update.html
UPDATE returns the number of rows that were actually changed. The
mysql_info() C API function returns the number of rows that were
matched and updated and the number of warnings that occurred during
the UPDATE.
Use the ANSI standard CASE function, or the mysql only least function as in the other answer
UPDATE player
SET health = CASE WHEN health + [potion] > max_health
THEN max_health
ELSE health + [potion]
END CASE
WHERE player_id = [player_id]