[Tutorial] [MySQL] Table structure and foreign keys
#21

Aha, nice tutorial.

I just came back after a few years and im impressed by how much the samp community is improving...

1 thing I didnt notice was that you didnt mention the relationship types? Which is the biggest thing about relational databases (1 to many, 1 to 1, many to many)... I know the tutorial is on foreign keys, but the type of relationship is important with this
Reply
#22

Quote:
Originally Posted by DarrenReeder
Посмотреть сообщение
I know the tutorial is on foreign keys, but the type of relationship is important with this
If you follow the normalization forms, separation of data into different tables is is automatically forced because there really is no other way of doing it.

Let's say you have a "users" and a "items" table. The logical reasoning is, "a user HAS items", or more importantly "1 user has many items". Or if you want to be absolutely correct, and this is very important while designing a database, "1 OR 0 users CAN HAVE 0 or more items". When you transorm this into a ERD and later into a logical and normalized database you'll automatically end up with a 1-to-many table. As in, 1 "user" can have many "items". It's pure logic, you end up with a certain relation type just because there is not other way of doing it.

Asking which relation you should use is not a fair question. Instead, ask yourself how your data should be organized and what relation they ave to each other.

Database Design is for most people here a quite advanced topic, but I'm glad it's being brought up because if you work with a relational database there really is nothing more important.
Reply
#23

I've tried your table design and connected several tables with the accounts table. But sometimes following error comes up:

Код:
[ERROR] CMySQLQuery::Execute[] - (error #1452) Cannot add or update a child row: a foreign key constraint fails (`nefserver`.`achievements`, CONSTRAINT `achievements_ibfk_1` FOREIGN KEY (`id`) REFERENCES `accounts` (`id`) ON DELETE CASCADE ON UPDATE CASCADE)
Код:
CREATE TABLE IF NOT EXISTS `accounts` (
  `id` int(10) unsigned NOT NULL AUTO_INCREMENT,
  `name` varchar(24) NOT NULL,
   other stuff here,
   PRIMARY KEY (`id`),
   UNIQUE KEY `name` (`name`)
) ENGINE=InnoDB  DEFAULT CHARSET=latin1 AUTO_INCREMENT=45802 ;


CREATE TABLE IF NOT EXISTS `achievements` (
  `id` int(10) unsigned NOT NULL,
  `type` tinyint(3) unsigned NOT NULL,
  `unlockdate` int(10) unsigned NOT NULL,
  KEY `id` (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1;

--
-- Constraints for table `achievements`
--
ALTER TABLE `achievements`
  ADD CONSTRAINT `achievements_ibfk_1` FOREIGN KEY (`id`) REFERENCES `accounts` (`id`) ON DELETE CASCADE ON UPDATE CASCADE;
Any idea, Vince? :/

Edit: Found the problem, the query tried to insert into `achievements` using a index key not available in `accounts`.
Reply
#24

Hi. Vince, Sorry for off topic, I also tried to pm you or wall you but it wasn't allowed. So, I saw your post regarding the efficient way of optimizing the script lines but the thread I made has been delete for unknown reason. Anyways, just a question the code you've posted is also like the same way of using Indentation Styles? Like..

Allman style
Код:
COMMAND:heal(playerid, params[])
{
    if(IsPlayerAdmin(playerid))
    {
        SetPlayerHealth(playerid, 100);
    }
    else
    {
        Kick(playerid);
    }
}
K&R style
Код:
COMMAND:heal(playerid, params[]) {
    if(IsPlayerAdmin(playerid)) {
        SetPlayerHealth(playerid, 100);
    } else {
        Kick(playerid);
    }
}
Reply
#25

You're adding the foreign key to the wrong table. Achievements is the child table, so that table should have the foreign key. Foreign key accountid references accounts id.
Reply
#26

Hi, sorry for the bump. Again facing problems with the query:

CREATE TABLE `Table1` (`Field` INT(11) NOT NULL, `Field1` VARCHAR(21) NOT NULL, PRIMARY KEY (`Field`));
CREATE TABLE `Table2` (`Field1` VARCHAR(21) NOT NULL, `Field` INT(11) NOT NULL DEFAULT '0');

ALTER TABLE `Table2`
ADD FOREIGN KEY (`Field1`)
REFERENCES `Table1` (`Field1`)
ON UPDATE CASCADE
ON DELETE CASCADE

SQL Error (1005): Can't create table 'SAMP_294.#sql-1673_41aa' (errno: 150) Foreign key constraint is incorrectly formed *

EDIT: Looks like my `Field1` in `Table1` should be a unique index - sadly this wont work as i already have Field as a primary key.
Reply
#27

I will read again this to refresh my memory
Reply
#28

deldeleted
Reply
#29

Works for sqlite?
Reply
#30

I don't know if SQLite actually enforces relations the way MySQL does but the theory should be all the same.
Reply
#31

SQLite of samp is horribly outdated.
Reply
#32

I am quite new to understanding the way mysql works as a whole. Especially Table structure and foreign keys, I've got a system with basically the exact same system as your explanation. However I'm not sure how to add to the table and also how to load from the table. Could someone please explain and show me how to do it? Thank you

PHP Code:
mysql_format(ServerMySQL,string,sizeof(string),"CREATE TABLE IF NOT EXISTS `Vehicles` (\
        `uID` int(11) NOT NULL,\
        `VehID` int(11) unsigned NOT NULL AUTO_INCREMENT,\
        `Type` tinyint(7) NOT NULL DEFAULT '0',\ 
        `Model`  tinyint(7) NOT NULL DEFAULT '0',\
        `Locked` tinyint(7) NOT NULL DEFAULT '0',\
        `Fuel` tinyint(7) NOT NULL DEFAULT '0',\
        `CarX` float NOT NULL,\
        `CarY` float NOT NULL,\
        `CarZ` float NOT NULL,\
        `CarR` float NOT NULL,\
        `VehNum` char(9) NOT NULL,"
);
        
mysql_format(ServerMySQL,string,sizeof(string),"%s\
        `SavedWeaps0` tinyint(7) NOT NULL DEFAULT '0',\
        `SavedAmmos0` tinyint(7) NOT NULL DEFAULT '0',\
        `SavedWeaps1` tinyint(7) NOT NULL DEFAULT '0',\
        `SavedAmmos1` tinyint(7) NOT NULL DEFAULT '0',\
        `SavedWeaps2` tinyint(7) NOT NULL DEFAULT '0',\
        `SavedAmmos2` tinyint(7) NOT NULL DEFAULT '0',"
,string);
        
mysql_format(ServerMySQL,string,sizeof(string),"%s\
        `SavedWeaps3` tinyint(7) NOT NULL DEFAULT '0',\
        `SavedAmmos3` tinyint(7) NOT NULL DEFAULT '0',\
        `SavedWeaps4` tinyint(7) NOT NULL DEFAULT '0',\
        `SavedAmmos4` tinyint(7) NOT NULL DEFAULT '0',\
        PRIMARY KEY (`VehID`)) ENGINE = InnoDB DEFAULT CHARSET=latin1"
,string);
        
mysql_tquery(ServerMySQLstring);
        
mysql_tquery(ServerMySQL"ALTER TABLE `Vehicles` ADD FOREIGN KEY (`uID`) REFERENCES `Users` (`uID`) ON UPDATE CASCADE ON DELETE CASCADE");
        
mysql_format(ServerMySQL,"CREATE TABLE IF NOT EXISTS `Vehicle_Mods` (\
        `VehID` int(11) unsigned NOT NULL,\
        `mod_model` smallint(5) unsigned NOT NULL,\
        `Col1` tinyint(7) unsigned NOT NULL DEFAULT '0',\
        `Col2` tinyint(7) unsigned NOT NULL DEFAULT '0',\
        `CarPaint` smallint(7) unsigned NOT NULL DEFAULT '255',\
        PRIMARY KEY (`VehID`, `mod_model`)) ENGINE = InnoDB DEFAULT CHARSET=latin1"
);
        
mysql_tquery(ServerMySQLstring);
        
mysql_tquery(ServerMySQL"ALTER TABLE `Vehicle_Mods` ADD FOREIGN KEY (`VehID`) REFERENCES `Vehicles` (`VehID`) ON UPDATE CASCADE ON DELETE CASCADE"); 
Reply
#33

Bump?
Reply
#34

Bump?
Reply
#35

read the red marks, he already stated that this tutorial is intended for people who already have general knowledge in MySQL (who already are familiar with MySQL functions and how to work with the), this is why you're not getting answers, nor from Vince.
Its not intended to guide people through MySQL, but rather give tips&tricks on how to improve your existing knowledge.
You're simply - kinda of- showing off you ignored the first post.


Refer to this tutorial, I haven't read the tutorial, but he do guide through table creation, structure, how to modify them and manage.
https://sampforum.blast.hk/showthread.php?tid=485633
Reply
#36

I think you misunderstood me. I know how to save to databases and I know MySQL functions, I'm just new to the idea of having multiple tables for the same sort of thing. I think I reworded my question wrong; I was just wanting advice on how to insert the car mod into the child board of vehicle_mods and how to load from it. Plus if this isn't the place to ask questions where do I go? Go post a topic on the scripting help board? Well...Aren't you meant to look around for a similar situation you're in or topic that you're looking for and read it and if you have any questions ask? Because if I'm not allowed to post here then I'll go make another topic on the exact same thing in the Scripting Help board.
Reply
#37

Quote:
Originally Posted by Tass007
View Post
I think you misunderstood me. I know how to save to databases and I know MySQL functions, I'm just new to the idea of having multiple tables for the same sort of thing. I think I reworded my question wrong; I was just wanting advice on how to insert the car mod into the child board of vehicle_mods and how to load from it. Plus if this isn't the place to ask questions where do I go? Go post a topic on the scripting help board? Well...Aren't you meant to look around for a similar situation you're in or topic that you're looking for and read it and if you have any questions ask? Because if I'm not allowed to post here then I'll go make another topic on the exact same thing in the Scripting Help board.
I referred to the misknowledge in how to add columns.

So for the answer for your question, I don't really understand deeply the code you've sent, but I can extend the explanation on the first post.

Which is basically kind of building a NoSQL, but in SQL


Say you're given an entire row, you have many columns.
You have player data, name, password etc, and then you have a set of columns for the private vehicle, private house and many other things.
Everything in one row.

Now, a few months pass, and you feel like having to increase the number of private things.
Like, 2 private houses, 2 private vehicles, two private weapons on spawn.

So what would you typically do if you already have everything in one table? You'd more columns
But hey, there are already HouseID and HousePosX Y and Z, how do I scale that?
Most people would just add a number to it, to indicate a multi set of things.

So now you're basically building a really long table horizontally. ( <- (horizontal) -> )

So now we approach the first issue, and that's a mess of data, you open your table and see lots of data and it only grows bigger downside and rightside, because you're building horizontally as well with columns.


And here comes the the foreign keys in:
Lets erase all the things we had until now except the user data.

You by now, probably have the player id, name, password and a bit of other tasty data you've collected.

Now, lets imagine we're creating a separate table called `houses`, `vehicles`.
Houses will hold a preset of house data that we created all over GTA and vehicles will need to be created dynamically - as people buy more and more vehicles.

Now, you'd probably create the normal columns for them, and add to the end of each table an id, such as `OwnerId` which will hold the account id of the owner.

And here comes the important stuff, make the ownerid be a foreign key which refrences to the player's account id.
Which means

PHP Code:
CREATE TABLE Vehicles (
    
ID int NOT NULL,
    
VehicleID int NOT NULL,
    
VehiclePlate int NOT NULL,
    
AccountID int,
    
PRIMARY KEY (ID),
    
FOREIGN KEY (AccountIDREFERENCES accounts(ID)
); 
Which basically means:

Create a table with this data:
ID,
VehicleID,
VehiclePlate
AccountID,

Now make a conection between AccountID column here with `table` accounts ( column `ID` )

And now, the PRIMARY KEY is the referenced key.
in `accounts` table, the ID should be a primary key.

Primary key basically is the key which represents these rows, and you can link from any other table to this
In our case, the account ID is the one we link to.

Now, as for the houses, we do the same, but for OwnerID

PHP Code:
CREATE TABLE Houses (
    
ID int NOT NULL,
    
HouseLabel int NOT NULL,
    
HouseCost int NOT NULL,
    
OwnerID int,
    
PRIMARY KEY (ID),
    
FOREIGN KEY (OwnerIDREFERENCES accounts(ID)
); 
Now, what are the advantages of this after all
First of all its not messy.
Second, its scalable, which means you can link as many rows you wish to one player.
So you can now give a player buy 2 houses or 1337 houses, as long as you link the account right with the foreign keys and primary.

(Remember that you have to create a primary key for the "reference to this")

But be aware of the other things I haven't mentioned, but is written in the first post under `Creating relations`


I hope I explained it well enough and correctly
Reply
#38

Hi, thanks for trying to help me out by putting all that time into the post unfortunately I already know that stuff. I don't think I'm asking the right question in order to get the answer I'm looking for but I'll try again. I have two tables vehicles and vehicle mods they have primary keys and all that so they will update with one another etc... I understand that in order to save data into the vehicle mods table that I need to use insert into, however what I don't know is what I'm meant to be saving as model id and where I would get said modelid from and how would I load multiple tables and adding that modelid onto the car. Hopefully that helps you understand the answer I'm looking for.
Reply
#39

Sorry for bumping this topic but i still don't understand a thing.
A player mod his car , server insert the mod into the vehicle_mods and the player reconnect and the server loads the mods for his vehicle.
But if player change the car spoiler. How the server knows that he needs to rewrite a mod from vehicle_mods so there will be no double spoilers?
I mean i want to know how to make the system to not have duplicate mods(2 spoilers or 2 bumpers) because as far i see the database design it not allow to be 2 same mod ids but not same 2 types of mods
Reply


Forum Jump:


Users browsing this thread: 1 Guest(s)