Validate Using Enum in MYSQL - php

i have a problem with validate my query in mysql using enum. as i know mysql doesnt support with constraint so i use enum
Example code :
alter table jewerly modify gender enum('M','F') NOT NULL DEFAULT 'M';
it run well if i use like above, but i have a problem to validate in another condition.
i want to modify validation with enum for : inputted productID format must like : PR[xxx], xxx means the number. if we use constraint, it will be like 'PR[0-9][0-9][0-9]',
but i dont know how to use in enum.
alter table jewelry modify jewelid enum('PR[0-9][0-9][0-9]') NOT NULL;
i tried this query above but it doesnt work.. any idea?

What you are attempting to do makes no sense in MySQL. You seem to be using a regular expression format for an enum definition.
Although enum can be used for such validation, it has some drawbacks. There are limits to the number of values, for instance. Changing the type can be problematic -- such as fixing a spelling error.
Instead, you might consider use foreign keys for this purpose:
create table ref_jewelid (
jewelid varchar(255)
);
create table jewelry (
. . .
constraint fk_jewelid foreign key (jewelid) references ref_jewelid(jewelid)
);
You would then populate ref_jewelid with the valid values, perhaps using a spreadsheet to generate the names. You might even take this one step further and have jewelid be a bona fide numeric id, with the name being one attribute of it. That is the approach I would probably take.

Related

MySQL tables of constants

I'm just trying out foreign keys for the first time and I'm worried I'm getting a little carried away.
For several of my class variables and their corresponding database records, I've got sets of constants which limit the values that can be chosen. These are currently set and validated using PHP.
What I'm wondering is, should I make tables of these constants in MySQL and lock them into foreign keys? Is this worth the trouble, or is the PHP definitions enough?
For example, say I've got a table transactions, with PHP constants defined for 'credit' and 'debit'.
transactions has a type field which indicates whether the transaction was credit or debit.
Should I create another table (transactions_constants or something) that defines the constants used in transactions(type) and foreign-key them together?
Yes, you should. With FK:
Your database has a more specific interface.
The DB has a clear structure (a DB should be readable regardless of code).
You can avoid accidents with inserts/updates by other DB clients (like PMA).
But you can also have copy of table with consts as consts in PHP (I use codegeneration for this).
Yes, you could use enum. But read 8 Reasons Why MySQL's ENUM Data Type Is Evil first.
In your case, creating a separate table for the transaction type is probably overkill. You can make your type column an enum to help with limiting the allowed values on the database side.
If transaction types had more data associated with them that you wanted to store in the database then a separate table and a foreign key relationship would be the way to go.
If your values set change rarely, you should use MySQL ENUM datatype, and you should turn on MySQL restrict mode. For example:
If your table like that:
CREATE TABLE `table` (
id int unsigned primary key auto_increment,
type enum('credit','debit') not null,
);
the strict mode will help you when you execute a query like
update table `table` set `type` = 'credit1 ' where id = 2
# strict mode on: an error will be raised
# strict mode off: `type` will be '' (empty string)
The above query can not be run if your code is perfect. It's up to you.

Joomla mysql tables.php syntax

Building a component, version 1.5 (gonna be cut loose soon, I know, but it's what I need to work with.)
Issue with the /admin/tables/mycom.php file. (In which mycom is whatever the component name is)
I'm not following the use of this file. From reading the walkthrough, it's creating a table class that extends JTables.
Now, some of the DB column names I'm using have 'space' characters in them. ie, 'field 1' instead of 'field1' (don't ask me, it's not my data.)
The sytax for identify these fiels is:
$myfield = null
It says these reference your fields in the mySQL table, but my field names include space which wouldn't work with this syntax.
Any help understanding this class, it's php file and what it's use is would be much appreciated.
By creating a JTable class for your table most of the code for editing your table is done for you. I suggest you familiarize yourself with JTable in the Joomla library so you know what functions are pre-written for you that you can use and override.
As to the issue of your DB column name having spaces... well to be honest it's just a bad idea. Here are some MySQL naming convention best practices for you....
always use lowercase with underscores instead of CamelCase. Goes for both the table and column names. (first_name instead of FirstName, address_1 instead of Address1
every table should have an "id" column as the primary key, don't call it UserID or anything else
the table name should be plural (profiles, supports, etc.)
foreign keys should have the singular name of the related table followed by underscore id. For example: "profile_id" or "support_id".
If you can I would recommend you do some ALTER TABLE updates to the MySQL e.g.
ALTER TABLE `#__example` CHANGE `Field 1` `field_1` VARCHAR(50) NOT NULL DEFAULT 'empty';

Enum vs Reference table vs Lookup class

While I'm designing a MySQL database for a dating website, I have come with the doubt of how to store the referenced data. Currently the database has 33 tables and there are nearly 32 different fields who need to be referenced. We have to consider as well that many of these elements need to be translated.
After been reading several opinions, I have almost dismissed to use enum like:
CREATE TABLE profile (
'user_id' INT NOT NULL,
...
'relationship_status' ENUM('Single','Married') NOT NULL,
...
);
And normally I would be using a reference table like:
CREATE TABLE profile (
'user_id' INT NOT NULL,
...
'relationship_status_id' INT NOT NULL,
...
);
CREATE TABLE relationship_status (
'id' INT NOT NULL,
'name' VARCHAR(45) NOT NULL,
PRIMARY KEY ('id')
);
But it might be over-killed to create 32 tables so I'm considering to code it in PHP like this:
class RelationshipStatusLookUp{
const SINGLE = 1;
const MARRIED = 2;
public static function getLabel($status){
if($status == self::SINGLE)
return 'Single';
if($status == self::MARRIED)
return 'Married';
return false;
}
}
What do you think? Because I guess it could improve the performance of the queries and also make easier the development of the whole site.
Thanks.
Definitely a good idea to steer clear of ENUM IMHO: why ENUM is evil. Technically a lookup table would be the preferred solution although for simple values a PHP class would work. You do need to be careful of this for the same reasons as ENUM; if the values in your set grow it could become difficult to maintain. (What about "co-habiting", "divorced", "civil partnership", "widowed" etc). It also not trivial to query for lists of values using PHP classes; it's possible using reflection but not as easy as a simple MySQL SELECT. This is probably one of those cases where I wouldn't worry about performance until it becomes a problem. Use the best solution for your code/application first, then optimise if you need to.
enum fields present some issues:
Once they're set, they can't easily be changed
'relationship_status' ENUM('Single','Married') NOT NULL,
would need 'Civil Partnership' adding in this country nowadays
You can't easily create a dropdown list of options from the enum lists
However, data onthe database can be subjected to referential integrity constraints, so using a foreign key link against a reference table gives you that degree of validation without the constraints of an enum.
Maintaining the options in a class requires a code change for any new options that have to be added to the data, which may increase the work involved depending on your release procedures, and doesn't prevent bad data being inserted into the database.
Personally, I'd go for a reference table
First off, you wouldn't need id and relationship_status_id in the Relationship_status table.
Personally, I would use an enum unless you need to associate more data than just the name of the person's relationship status (or if you foresee needing to expand on this in the future). It will be much easier when you're looking at the database to see what's what if it is in an easily readable language versus having to query against a second table.
When you are considering performance, sure it's faster to query a table by a unique ID but you have to track that relationship and you will always be joining multiple tables to get the same data. If the enum solution ends up being slower, I don't think it will be enough that the human brain will be able to perceive the difference even with large data sets.

SchemaGenerator additional VARCHAR field, why?

When generating a table from this model:
function init()
{
parent::init();
$this->addField('person_id')->refModel('Model_Person')->mandatory(true);
$this->addField('username')->mandatory(true);
$this->addField('password')->mandatory(true);
}
I get this SQL statement:
create table users (
id int auto_increment not null primary key,
person_id varchar(255),
person int(11),
username varchar(255),
password varchar(255));
In this SQL statement i get the opposite of what is said in the tutorial:
Calling refModel with a field name ending in "_id" will actually create 2 field definitions. "publisher_id", for instance, will be defined as integer and will have type "reference", and a field "publisher" will also be added, with exactly same properties - but it will be a calculated field and will use sub-select to determine the value.
I want to know:
Is the generated SQL statement correct?
What does this VARCHAR additional generated field do? (I made CRUD and when added new records, the value of this field was saved as NULL).
When using refModel(), if i used the model name only ('Person') i got an error (Unable to include Person.php), i had to use the complete class name ('Model_Person'). Is this ok? shouldn't i be able to use the model name only?
The mandatory() doesn't use NOT NULL, is there way to do this?
The generated SQL statement is not correct. It's a bug in generator. You need just one field o type "int" ending with the _id.
The reason why it does this, is because refModel() actually creates two fields in the model, one of which is used for editing (_id) and other is used for listing data (as a sub-query)
When you use refModel, you should use "Model_Person". The consistency between refModel, setModel and other fields will be improved in 4.2, it's not done due to compatibility reasons.
The SQL Generator by it's nature is incomplete and it can't be complete, so it's better that schema is reviewed anyway. For instance you might have some fields which are not defined in "Model". Also I prefer that developers pay attention to SQL as it might not reflects models precisely, one model may use multiple tables through join or models may inherit each then add more field definitions there.
mandatory() is a model-level requirement which works similarly to other validations. While MySQL could handle the "mandatory" condition, it wouldn't be able to handle others. Besides, you may remove "mandatory" when you inherit models.
I'll try to add a guide on effective use of Models in Agile Toolkit.

MySQL: UPDATEing a row with no guaranteed unique field

I am working with an old MySQL table, which serves as a log of sorts. It looks like
CREATE TABLE `queries` (
`Email` char(32) NOT NULL DEFAULT '',
`Query` blob,
`NumRecords` int(5) unsigned DEFAULT NULL,
`Date` date DEFAULT NULL
) ENGINE=MyISAM DEFAULT CHARSET=latin1;
Now, I need to be able to UPDATE the records in this table (don't ask why, I don't know). Normally, I would just do
UPDATE table SET ... WHERE unique_column = value
But in this case, I don't have a unique column to work from.
Is there a workaround for this, or am I just going to have to push to put in a nice, standard INT NOT NULL AUTO_INCREMENT?
UPDATE queries
SET ...
WHERE Email = value1
AND Query = value2
AND NumRecords = value3
AND Date = value4
LIMIT 1;
A unique identifier is the only reliable way of doing this. Just add an auto_increment column and be done with it.
For exhaustive info including some workaround approaches (none of them perfect though!) check this question, where the OP had a table without a unique identifier and no way to change it.
Update: As Doug Currie points out, this is not entirely true: A unique ID is not necessary as such here. I still strongly recommend the practice of always using one. If two users decide to update two different rows that are exact duplicates of each other at the exact same time (e.g. by selecting a row in a GUI), there could be collisions because it's not possible to define which row is targeted by which operation. It's a microscopic possibility and in the case at hand probably totally negligeable, but it's not good design.
There are two different issues here. First, is de-duping the table. That is an entirely different question and solution which might involve adding a auto_increment column. However, if you are not going to de-dup the table, then by definition, two rows with the same data represent the same instance of information and both ought to be updated if they match the filtering criteria. So, either add a unique key, de-dup the table (in which case uniqueness is based on the combination of all columns) or update all matching rows.
In case you didn't know this, it will affect performance, but you don't need to use a primary key in your WHERE clause when updating a record. You can single out a row by specifying the existing values:
UPDATE queries
SET Query = 'whatever'
WHERE Email = 'whatever#whatever.com' AND
Query = 'whatever' AND
NumRecords = 42 AND
Date = '1969-01-01'
If there are duplicate rows, why not update them all, since you can't differentiate anyway?
You just can't do it with a GUI interface in MySQL Query Browser.
If you need to start differentiating the rows, then add an autoincrement integer field, and you'll be able to edit them in MySQL Query Browser too.
Delete the duplicates first. What's the point of having duplicate rows in the table (or any table for that matter)?
Once you've deleted the duplicates you can implement the key and they your problem is solved.

Categories