Best way to parse text into SQL statements? - mysql

I'm working on a web app, and I only have console access to MySQL. I have a textfile, I want to insert the data into DB, but to do that will I need to make an interpreter first to convert lines from textfile into insert statement? or is there an easier way I'm overlooking?
I have a text file like this (the format is at the bottom of this post)
I want to take each line from the file, do some string manipulation, and insert it into database.
DB looks like this
CREATE TABLE website.Categories (
ID int NOT NULL,
CategoryName varchar(500) NOT NULL,
PRIMARY KEY (ID)
);
CREATE TABLE website.Questions(
ID int NOT NULL,
Category int,
QuestionText varchar(5000) NOT NULL,
AnswerText varchar(5000) NOT NULL,
PRIMARY KEY (ID)
);
I can make a JavaScript interpreter that "compiles" the text file into a bunch of MySQL insert statements, and I can then just run those statements, can someone please verify if that's the easiest way to go about this?
Example in pseudocode of what I will have to do:
- go one line at a time
- initialize counter
- take first line, surround it with "INSERT INTO 'website.categories' VALUES (_____)
- WHILE line not blank, take every line after that, split string using '?' as separator
- "INSERT INTO 'website.questions' VALUES (counter, __question___, __answer___)
- when blank increment counter
- insert next line into categories
- repeat
This is what the text file looks like:
chemistry
what is the formula for hydrogen peroxide?h2o2
what is the state of matter of water at room temperature?liquid
what is the lightest element?hydrogen
which silvery element was used in early thermometers?mercury
what does water turn into when boils?Steam
what element is glass made from?Silicon
geography
what is the capital of Austrailia?Canberra
what is the capital of Turkey?Ankara
what is the capital of Malaysia?Kuala Lumpur
what ocean is to the west of the United States?pacific
what ocean is to the east of Canada?atlantic
Which is the largest country in the world?Russia
Which river flows through Rome?Tiber
In which country is Mount Kilimanjaro?Tanzania
what is the longest river in the world?Nile
on which continent will you find Brazil?South America
On which continent are the Atlas Mountains?Africa
animals
which country is known for having pandas?China
what animal is known for eating bamboo?panda
which animal carries babies in its pouch?kangaroo
what are eggs of salmon called?roe
which animal has stripes?zebra
what is the fastest land animal?Cheetah
how many hearts do octopuses have?3
what is the baby goat called?kid
what do you call an animal that eats plants?herbivore
what is the longest snake in the world?Python
what is a female donkey called?Jenny
Which animal is the Florida Cracker?A Sheep
instruments
which device is used to measure temperature?thermometer
who invented radio?marconi
who invented waste dumpsters?demptser
what gas is usually filled in lighters?butane
what does a manometer measure?Pressure
physics
what unit is sound loudness measured in?decibel
what is the unit of power?watt
which circuit component is known for storing charge?capacitor
what is the unit of electrical resistance?ohm

I was able to easily accomplish this with Java, I thought it would take hours but no only took less than 10 minutes.
Scanner myReader = new Scanner(myObj);
while (myReader.hasNextLine()) {
String data = myReader.nextLine();
if(data.equals("")) {
counter++;
}else if(data.contains("?")){
String lol[] = data.split("\\?");
System.out.println("INSERT INTO website.Questions (ID,Category,QuestionText,AnswerText) Values (" +counter2+","+ counter + ",'"+lol[0]+"', '"+ lol[1]+"');");
counter2++;
}else{
System.out.println("INSERT INTO website.Categories (ID, CategoryName) Values ("+ counter +", '" + data +"');");
}

Related

Understanding Mutual Information on Titanic Dataset

I was reading about Mutual Information on the Kaggle courses: https://www.kaggle.com/code/ryanholbrook/mutual-information
After that I tried it out on the Titanic Competition Dataset and I encountered a weird behaviour .
I will post the code further below.
I ranked all the features with mutual information and received the following output:
PassengerId 0.665912
Name 0.665912
Ticket 0.572496
Cabin 0.165236
Sex 0.150870
Fare 0.141621
Age 0.066269
Pclass 0.058107
SibSp 0.023197
Embarked 0.016668
Parch 0.016366
According to the documentation
Mutual information (MI) [1] between two random variables is a non-negative value, which measures the dependency between the variables. It is equal to zero if and only if two random variables are independent, and higher values mean higher dependency.
From my point of view at least PassengerId should be independent as well as the name. because I used factorize() on all objects. Which leaves me with 100% unique values for both Id and Names. There are in total 891 rows in the training dataset.
# number of unique values for top 2 MI
print(X_mi["PassengerId"].nunique())
print(X_mi["Name"].nunique())
891
891
My question is how does this happen? And why does PassengerId and Name with all unique values score even higher than lets say Age or Sex?
I followerd the Kaggle course on the link above. Only difference should be that I used
from sklearn.feature_selection import mutual_info_classif
instead of
from sklearn.feature_selection import mutual_info_regression
because my target is a discrete target.
Here is the relevant code:
X_train_full = pd.read_csv("/kaggle/input/titanic/train.csv")
X_test_full = pd.read_csv("/kaggle/input/titanic/test.csv")
X_mi = X_train_full.copy()
y_mi = X_mi.pop("Survived")
# Label encoding for categoricals
for colname in X_mi.select_dtypes("object"):
X_mi[colname], _ = X_mi[colname].factorize()
# fill all NaN values of age with mean and cast type to int
X_mi["Age"] = X_mi["Age"].transform(lambda age: age.fillna(age.mean()))
X_mi["Age"] = X_mi["Age"].transform(lambda age: age.astype("int"))
# cast fare type to int
X_mi["Fare"] = X_mi["Fare"].transform(lambda fare: fare.astype("int"))
# All discrete features should now have integer dtypes (double-check this before using MI!)
discrete_features = X_mi.dtypes == int
from sklearn.feature_selection import mutual_info_classif
def make_mi_scores(X, y, discrete_features):
mi_scores = mutual_info_classif(X, y, discrete_features=discrete_features)
mi_scores = pd.Series(mi_scores, name="MI Scores", index=X.columns)
mi_scores = mi_scores.sort_values(ascending=False)
return mi_scores
mi_scores = make_mi_scores(X_mi, y_mi, discrete_features)
print(mi_scores) # show features with their MI scores
Any explanation or suggestions what I might have done wrong?
From Data Analytics point of view I might have some mistakes but how does a fully unrelated feature like PassengerId score so high and higher than the others?
Thank you :)

Convert Dapper raw SQL Result to Nested JSON Array

I have developed a web api in .Net Core 5 which uses dapper to run a tabled valued function and return the SQL results. These results are then used to fill various select boxes on the front end in VueJS. However, when I began to build out my front end more I realized my JSON arrays could be nested to really help reduce the number of requests I make to the server as my select boxes are dependent. For instance, one select box includes states and then next select box relates to the cities in those states. Adjusting the tabled value function to return a single table was easy by adding a innerjoin between my state table in the database and the cities table. The joining key was a field called STATE_ID. Therefore I just have multiple rows due to multiple cities per state. So now what I am trying to figure out is how to take this result in my web api and my table valued function result without the use of models into a nested json array such that my results are as follows:
[{state: 'Maryland', cities :[{city: 'Baltimore'}, {city: 'Harford County'}]} ,
{state: 'Pennsylvania', cities :[{city: 'York'}, {city: 'Fawn Grove'}]}]
Table valued function result from A2Q00001_StateInfo(USERNUMBER):
| State_ID | State_Name | City_Name |
|---------------------|------------------|---------------------|
| 1 | Maryland | Baltimore |
| 1 | Maryland | Harford County |
| 2 | Pennsylvania | York |
| 2 | Pennsylvania | Fawn Grove |
My controller is as follows:
public ActionResult StateAndCities([FromQuery] String USERNUMBER)
{
//We have parameters here just in case we want to use them
IEnumerable queryResult;
String query = "select * from dbo.A2Q00001_StateInfo(#USERNUMBER);";
using (var connection = new SqlConnection(connectionString))
{
queryResult = connection.Query(query, new { USERNUMBER = USERNUMBER });
}
return Ok(queryResult);
}
All of the tutorials I have seen online use models to create the nested JSON object and return it however I am not sure how to create the nested object using the serialization in the Ok() function in asp.net core. Is this even posssible or do I need to perform operations on the queryResult from the dapper query? Any point in the right direction would be great.
My advice: split this into steps. I'm guessing your A2Q00001_StateInfo UDF here returns a State and City column (edit: I was close, it was State_Name, via the edit), among other things. So first step: let's just read that:
class SomeType
{
public string State_Name { get; set; }
public string City { get; set; }
}
//...
var queryResult = connection.Query<SomeType>(
"select State_Name, City from dbo.A2Q00001_StateInfo(#USERNUMBER);",
new { USERNUMBER }).AsList();
This gets our data from the database into local memory. Note that I filtered out irrelevant columns to reduce overheads.
Now, the next step is to structure that data - it looks like you want to aggregate by state, and create an array of the cities in each; so: let's do that:
var structured =
from grp in queryResult.GroupBy(x => x.State_Name)
select new
{
state = grp.Key,
cities = grp.Select(row => new { city = row.City }).ToArray()
};
This gives us a projection (using anonymous types) that does the restructuring we want. Finally, we need to convert it to JSON; this might be as simple as:
return Ok(structured);
Or you might need to use the Json/JsonResult APIs directly. However, now that the data is structured: any JSON serializer should know what we want to do here.
Note: you probably can rewrite all this into a single expression, but: don't do that; you're not trying to impress the compiler - it won't care either way. Make the code clear and obvious for the next person who is going to need to touch it (which might well be you).

GeoLocation - Parsing //Formatted_Address?

I am playing with a new function in an AccessDB app to return Lat/Lon info from Hospital names. The following function provides what I need when I provide a Name & Address. I noticed (unexpected) the function returns a formatted address even if I provide JUST a valid hospital name. I think I can exploit this to backfill address info into my database.
It appears that Geocode.sRetAddress = .selectSingleNode("//formatted_address").Text is "mostly" consistent and easilly parsed to grab Address/City/State/ZIP info using "," as a delimiter. My complication is the rare occasion where a "Floor Number" is included in the formatted address string. My parsing routine fails.
I found this routine (not mine):
Option Explicit
Option Compare Database
'Public Type containing the geocoding of the postal address
Public Type tGeocodeResult
dLatitude As Double
dLongitude As Double
sRetAddress As String
sAccuracy As String
sStatus As String
End Type
'---------------------------------------------------------------------------------------
' Procedure : Geocode with Google Geocoding API v3
' Version : 1.01
' DateTime : 03/03/2011
' Author : Philben
' Purpose : converting addresses into geographic coordinates
' Parameter : No mandatory. string format or NULL
' Reference : http://code.google.com/intl/fr-FR/apis/maps/documentation/geocoding/index.html
' Remark : Query limit of 2,500 geolocation requests per day
' : A good accuracy is different of a good geocoding !!!
' : Minimum delay between two queries : >= 200 ms
'---------------------------------------------------------------------------------------
Public Function Geocode(Optional ByVal vAddress As Variant = Null, _
Optional ByVal vTown As Variant = Null, _
Optional ByVal vPostCode As Variant = Null, _
Optional ByVal vRegion As Variant = Null, _
Optional ByVal sCountry As String = "UNITED STATES+") As tGeocodeResult
On Error GoTo catch
Dim oXmlDoc As Object
Dim sUrl As String, sFormatAddress As String
If Not IsNull(vAddress) Then vAddress = Replace(vAddress, ",", " ")
sFormatAddress = (vAddress + ",") & _
(vTown + ",") & _
(vRegion + ",") & _
(vPostCode + ",") & _
sCountry
'To create the URL
sUrl = "http://maps.googleapis.com/maps/api/geocode/xml?address=" & sFormatAddress & "&sensor=false"
''XMLDOM to get the XML response
Set oXmlDoc = CreateObject("Microsoft.XMLDOM")
With oXmlDoc
.Async = False
If .Load(sUrl) And Not .selectSingleNode("GeocodeResponse/status") Is Nothing Then
'Status code
Geocode.sStatus = .selectSingleNode("GeocodeResponse/status").Text
'If a result is returned
If Not .selectSingleNode("GeocodeResponse/result") Is Nothing Then
'formatted_address
Geocode.sRetAddress = .selectSingleNode("//formatted_address").Text
'Accuracy
Geocode.sAccuracy = .selectSingleNode("//location_type").Text
'Latitude and longitude
Geocode.dLatitude = Val(.selectSingleNode("//location/lat").Text)
Geocode.dLongitude = Val(.selectSingleNode("//location/lng").Text)
End If
End If
End With
Set oXmlDoc = Nothing
Exit Function
catch:
Set oXmlDoc = Nothing
Err.Raise Err.Number, , Err.Description
End Function
Example Results (Geocode.sRetAddress - formatted address):
good: 100 S Raymond Ave, Alhambra, CA 91801, USA
good: 3040 Salt Creek Ln, Arlington Heights, IL 60005, USA
bad: 4th floor, 2450 Ashby Ave, Berkeley, CA 94705, USA
Question
Any clue if the "Floor" component of the Formatted Address can be excluded, or alternatively explicitly return JUST the desired components?
Thanks,
Mark Pelletier
PS> I am currently counting the number of "," in the string and conditionally handling the parsing task. But As a general purpose approach, there will likely be other exceptions I have not encountered yet.
I'm a bit of a beginner in XPath, but I think I can solve this:
Instead of:
'formatted_address
Geocode.sRetAddress = .selectSingleNode("//formatted_address").Text
Use:
'Build an address:
Geocode.sRetAddress = oXMLDoc.selectSingleNode("descendant::address_component[type='street_number']/short_name").text
Geocode.sRetAddress = Geocode.sRetAddress & " " oXMLDoc.selectSingleNode("descendant::address_component[type='route']/short_name").text
Geocode.sRetAddress = Geocode.sRetAddress & ", " oXMLDoc.selectSingleNode("descendant::address_component[type='locality']/short_name").text
Geocode.sRetAddress = Geocode.sRetAddress & ", " oXMLDoc.selectSingleNode("descendant::address_component[type='administrative_area_level_1']/short_name").text
Geocode.sRetAddress = Geocode.sRetAddress & " " oXMLDoc.selectSingleNode("descendant::address_component[type='postal_code']/short_name").text
Geocode.sRetAddress = Geocode.sRetAddress & ", " oXMLDoc.selectSingleNode("descendant::address_component[type='country']/short_name").text
to manually build up an adress based on components provided by the Google Maps geocode API.
Note that if you're parsing things like cities and states out of this, that's a rather silly thing to do, since they're just available in the XML document. You're better of reading them directly from the XML.
Just re-read and it looks like your specific situation is geared to just hospitals so you will not need to consider all of the issues listed here. I'll leave this up, though, in case someone else is looking to parse addresses containing more than just "floor". And still--you could consider the algorithm for finding just the "root".
I worked on a similar project where I needed to identify the "root" physical address and it can be way more complicated than meets the eye. There are SO many pitfalls to watch out for. I ended up having to build a full-on rules engine. Anticipate every possible combination and account for it.
-2 Main St 4th floor
-2 Main St 3rd floor
-2 Main St Unit 3
-4th floor 2 Main St
-Apt 3 2 Main street
-Apt 3 22 Rte 7
-2 Main st 1st floor
...many more
As a general rule you are usually trying to identify a section of the address formatted as "2 Main Street" where you have a number, a street name, and the suffix describing the street/road/drive, etc. Here is a general algorithm which is only the base. You'll need to expand.
If there are any commas, split the string into separate elements to be evaluated individually
Remove all punctuation in the address elements
Find index of the "Street" You'll have to have a fairly extensive list, but here are some:
Road, Rd, Street, St, Boulevard, Blvd, Blv, Way, Avenue, Ave, Kill, Drive, Dr, Lane, Ln, Path, Highway, Hwy, BiWay, Bwy, Expressway. Circle, Cir, Crossing, Xing, Route, Rte, Rural Route, RR
I'm sure you can think of more.
Find the right-most instance of one of those and work backwards from that index until you find a numeric value (or, more accurately, the index of the beginning of a contiguous set of numerical values).
- Make sure that numeric value is not part of the street name (i.e. "3rd Street), which means make sure the numeric value is not followed by a "rd" or "th" or "nd" or make sure it has a space following it. If it is, keep looking back until you find the numeric part of the street address.
- Once you find the numeric value you will likely have what you need. Grab everything between the numeric value and the "Street".
Other things to be careful of:
- Abbreviation for "Street" and for "Saint" are the same. as in "2 St Francis St"
- Abbreviation for "Doctor" and for "Drive" are the same. "3 Dr Jones Dr"
- "Route"s and "Highways" can have numeric values following them as in "2 Route 5"
- Abbreviations for the many incarnations of "Street/Drive" are very often buried in the street name. "3 Caveman Arrival St" contains "ave" and "rr" an "st"
- Numeric portions may also be written as a word as in "Three Main Street",
If you choose to try and identify unwanted sections of address instead of the desired section, you will likewise need to account for a plethora of potential situations:
Apartment, Apt, Suite, Ste, Floor, Fl, Unit, #, Flat, Box, POBox, PO, Building,, Bldg, Bld, Dorm, Room, Rm
Ultimately, you'll likely end up with many scenarios/exceptions you'd need to account for and many "Cases". You might also consider using regular expressions to identify them. Good luck!

acceptable url character replacement for apostrophes and hyphens

I have a string as such: My First - Recipe's I want to translate this into a readable URL.
I'd like to change the spaces to - however there already exists a hyphen in the string. Also, there is an apostrophe.
I read online that using underscores is bad in clean URLS which is why I want to use hyphens but i cannot figure out what to change the hyphen to when there already exists one as well as the apostrophe
While you can use Unicode in web-page URLs, in practice and for usability you're restricted in the characters they can use - for example, if you want to allow people to manually type-in the full address then it's best to avoid all non-alphanumeric characters, especially punctuation, and if possible also avoid visual-homographs such as L, l, 1, i, I, and so on.
So if you have a web-page for an article of writing whose internal title is "Kaajh'Káalbh!" then you'll want the URL-name to be kaajh-kaalbh.
Note that the conversion from "Kaajh'Káalbh!" to "kaajh-kaalbh" involves the loss of information - this is a "one-way function" - which is to say that given a particular output ("kaajh-kaalbh") it is not easy to determine the original input ("Kaajh'Káalbh!") - in this case it's because there can be multiple inputs that lead to the same output, so you cannot know what the original input is - because it could have been "Kaajh'Káalbh!" or "Kaajh Kaalbh" or "kaajh Kaalbh?" - and so on.
You could argue that you could still query the database and find which rows correspond to the input, and I imagine your query would look like this:
SELECT * FROM Articles WHERE GetUrlVersionOfTitle( Title ) = 'kaajh-kaalbh'
Where GetUrlVersionOfTitle is a function in your SQL that would perform the conversion like so:
GetUrlVersionOfTitle( x ) = x.ToLower().Replace( ' ', '-' ).Replace( '\'', '-' ).Replace( etc )...
...which means your query becomes non-Sargable (see also) and would have terrible runtime query performance (because the database system would need to run the function on every row in your table, every time - obviously that's not good). It also doesn't solve the problem of ensuring that at most 1 row has the same URL-name (to guarantee that only 1 row matches a given URL name input).
The solution then is to precompute the URL-name, store it in a separate column, and also have a UNIQUE constraint against it
CREATE TABLE Articles (
ArticleId int IDENTITY(1,1) NOT NULL PRIMARY KEY,
Title nvarchar(255) NOT NULL,
UrlTitle varchar(255) NOT NULL UNIQUE,
...
)
INSERT INTO Articles( Title, UrlTitle ) VALUES ( #title, #urlTitle )
(where #urlTitle is a parameter whose value is the precomputed URL-friendly version of Title).
And then it's simple to match the article corresponding to a given URL:
In ASP.NET MVC:
[Route("~/articles/{urlTitle}")]
public ActionResult GetArticle(String urlTitle) {
Article article
using( DbContext db = ... ) {
article = db.Articles.SingleOrDefault( a => a.UrlTitle == urlTitle );
}
return this.View( new ArticleViewModel( article ) );
}
In my own code, I generate URL-friendly titles by first converting text to a normalized Unicode representation, then stripping-out diacritics, and also dropping non-digit/letter characters, like so:
Note that this only really works for Latin script - I've never had to target a non-Latin system (e.g. Greek, Cyrillic, Arabic, Hebrew, Farsi etc) so YMMV, but the same principles apply:
public static String ConvertToUrlName(String title) {
if( title == null ) throw new ArgumentNullException(nameof(title));
// Convert to normalized Unicode
// see here: https://stackoverflow.com/a/249126/159145
title = title.Normalize( NormalizationForm.FormD );
StringBuilder sb = new StringBuilder( title.Length );
foreach(Char c in title) {
// If the character is a diacritic or other non-base character, then ignore it
if( CharUnicodeInfo.GetUnicodeCategory( c ) != UnicodeCategory.NonSpacingMark ) continue;
c = Char.ToLowerInvariant( c ); // convert to lower-case
if( Char.IsLetterOrDigit( c ) ) {
sb.Append( c );
}
else if( Char.IsWhiteSpace( c ) ) {
sb.Append( '-' );
}
// and ignore all other character classes, such as punctuation
}
String urlTitle = sb.ToString();
return urlTitle;
}
Ta-da.

How to to create unique random integer ID for primary key for table?

I was wondering if anybody knew a good way to create a unique random integer id for a primary key for a table. I'm using MySQL. The value has to be integer.
In response to: "Because I want to use that value to Encode to Base62 and then use that for an id in a url. If i auto increment, it might be obvious to the user how the url id is generated."
If security is your aim then using Base62, even with a "randomly" generated number won't help.
A better option would:
Do not re-invent the wheel -- use AUTO_INCREMENT
Then use a cryptographic hash function + a randomly generated string (hidden in the db for that particular url) to generate the final "unique id for that url"
If your're open to suggestions and you can implement it, use UUIDs.
MySQL's UUID() function will return a 36 chars value which can be used for ID.
If you want to use integer, still, I think you need to create a function getRandID() that you will use in the INSERT statement. This function needs to use random + check of existing ids to return one that is not used before.
Check RAND() function for MySQL.
How you generate the unique_ids is a useful question - but you seem to be making a counter productive assumption about when you generate them!
My point is that you do not need to generate these unique id's at the time of creating your rows, because they are essentially independent of the data being inserted.
What I do is pre-generate unique id's for future use, that way I can take my own sweet time and absolutely guarantee they are unique, and there's no processing to be done at the time of the insert.
For example I have an orders table with order_id in it. This id is generated on the fly when the user enters the order, incrementally 1,2,3 etc forever. The user does not need to see this internal id.
Then I have another table - unique_ids with (order_id, unique_id). I have a routine that runs every night which pre-loads this table with enough unique_id rows to more than cover the orders that might be inserted in the next 24 hours. (If I ever get 10000 orders in one day I'll have a problem - but that would be a good problem to have!)
This approach guarantees uniqueness and takes any processing load away from the insert transaction and into the batch routine, where it does not affect the user.
How about this approach (PHP and MySQL):
Short
Generate random number for user_id (UNIQUE)
Insert row with generated number as user_id
If inserted row count equal to 0, go to point 1
Looks heavy? Continue to read.
Long:
Table:
users (user_id int UNIQUE)
Code:
<?php
// values stored in configuration
$min = 1;
$max = 1000000;
$numberOfLoops = 0;
do {
$randomNumber = rand($min, $max);
// the very insert
$insertedRows = insert_to_table(
'INSERT INTO foo_table (user_id) VALUES (:number)',
array(
':number' => $randomNumber
));
$numberOfLoops++;
// the magic
if (!isset($reported) && $numberOfLoops / 10 > 0.5) {
/**
* We can assume that at least 50% of numbers
* are already in use, so increment values of
* $min and $max in configuration.
*/
report_this_fact();
$reported = true;
} while ($insertedRows < 1);
All values ($min, $max, 0.5) are just for explanation and they have no statistical meaning.
Functions insert_to_table and report_this_fact are not build in PHP. The are also as numbers just for clarify of explanation purposes.
You can use an AUTO_INCREMENT for your table, but give the users the encrypted version:
encrypted_id: SELECT HEX(AES_ENCRYPT(id, 'my-private-key'));
id: SELECT AES_DECRYPT(UNHEX(encrypted_id), 'my-private-key');
my way, for both 32bit and 64bit platform. result is 64bit
function hexstr2decstr($hexstr){
$bigint = gmp_init($hexstr, 16);
$bigint_string = gmp_strval($bigint);
return $bigint_string;
}
function generate_64bitid(){
return substr(md5(uniqid(rand(), true)), 16, 16);
}
function dbGetUniqueXXXId(){
for($i = 0; $i < 10; $i++){
$decstr = hexstr2decstr(generate_64bitid());
//check duplicate for mysql.tablexxx
if($dup == false){
return $decstr;
}
}
return false;
}
AUTO_INCREMENT is going to be your best bet for this.
Here are some examples.
If you need to you can adjust where the increment value starts (by default it's 1).
There is an AUTO_INCREMENT feature. I would use that.
See here more examples.