So this is more of a query of how one might go about doing this, I'm new to MySQL/PHP coding when it comes to more than the basics so I'm just wondering how one might set up an auto incrementing int where if two lastnames were the same it would count them.
I was unable to find anything on it while searching online but an example would be:
in the database we have 5 users
1. james smith 1
2. terry smith 2
3. john smith 3
4. jerry fields 1
5. tom straus 1
When these users register I need an int to be created that john smith was the 3rd person to have the same last name of smith while jerry fields is the first person with the last name fields etc. How might one do that?
The form I made is one that registers a user using a jquery/php ajax method but
I would like to add something similar to this so that it combines that number with their names to make a specific user ID.
As documented under Using AUTO_INCREMENT:
For MyISAM and BDB tables you can specify AUTO_INCREMENT on a secondary column in a multiple-column index. In this case, the generated value for the AUTO_INCREMENT column is calculated as MAX(auto_increment_column) + 1 WHERE prefix=given-prefix. This is useful when you want to put data into ordered groups.
Therefore, you could do:
CREATE TABLE my_table (
firstname VARCHAR(31) NOT NULL,
lastname VARCHAR(31) NOT NULL,
counter BIGINT UNSIGNED NOT NULL AUTO_INCREMENT,
PRIMARY KEY (lastname, counter)
) Engine=MyISAM;
INSERT INTO my_table
(firstname, lastname)
VALUES
('james', 'smith' ),
('terry', 'smith' ),
('john' , 'smith' ),
('jerry', 'fields'),
('tom' , 'straus')
;
See it on sqlfiddle.
Related
I have two tables in MySQL. Table Person has the following columns:
id
name
fruits
The fruits column may hold null or an array of strings like ('apple', 'orange', 'banana'), or ('strawberry'), etc. The second table is Table Fruit and has the following three columns:
fruit_name
color
price
apple
red
2
orange
orange
3
-----------
--------
------
So how should I design the fruits column in the first table so that it can hold array of strings that take values from the fruit_name column in the second table? Since there is no array data type in MySQL, how should I do it?
The proper way to do this is to use multiple tables and JOIN them in your queries.
For example:
CREATE TABLE person (
`id` INT NOT NULL PRIMARY KEY,
`name` VARCHAR(50)
);
CREATE TABLE fruits (
`fruit_name` VARCHAR(20) NOT NULL PRIMARY KEY,
`color` VARCHAR(20),
`price` INT
);
CREATE TABLE person_fruit (
`person_id` INT NOT NULL,
`fruit_name` VARCHAR(20) NOT NULL,
PRIMARY KEY(`person_id`, `fruit_name`)
);
The person_fruit table contains one row for each fruit a person is associated with and effectively links the person and fruits tables together, I.E.
1 | "banana"
1 | "apple"
1 | "orange"
2 | "straberry"
2 | "banana"
2 | "apple"
When you want to retrieve a person and all of their fruit you can do something like this:
SELECT p.*, f.*
FROM person p
INNER JOIN person_fruit pf
ON pf.person_id = p.id
INNER JOIN fruits f
ON f.fruit_name = pf.fruit_name
The reason that there are no arrays in SQL, is because most people don't really need it. Relational databases (SQL is exactly that) work using relations, and most of the time, it is best if you assign one row of a table to each "bit of information". For example, where you may think "I'd like a list of stuff here", instead make a new table, linking the row in one table with the row in another table.[1] That way, you can represent M:N relationships. Another advantage is that those links will not clutter the row containing the linked item. And the database can index those rows. Arrays typically aren't indexed.
If you don't need relational databases, you can use e.g. a key-value store.
Read about database normalization, please. The golden rule is "[Every] non-key [attribute] must provide a fact about the key, the whole key, and nothing but the key.". An array does too much. It has multiple facts and it stores the order (which is not related to the relation itself). And the performance is poor (see above).
Imagine that you have a person table and you have a table with phone calls by people. Now you could make each person row have a list of his phone calls. But every person has many other relationships to many other things. Does that mean my person table should contain an array for every single thing he is connected to? No, that is not an attribute of the person itself.
[1]: It is okay if the linking table only has two columns (the primary keys from each table)! If the relationship itself has additional attributes though, they should be represented in this table as columns.
MySQL 5.7 now provides a JSON data type. This new datatype provides a convenient new way to store complex data: lists, dictionaries, etc.
That said, arrays don't map well databases which is why object-relational maps can be quite complex. Historically people have stored lists/arrays in MySQL by creating a table that describes them and adding each value as its own record. The table may have only 2 or 3 columns, or it may contain many more. How you store this type of data really depends on characteristics of the data.
For example, does the list contain a static or dynamic number of entries? Will the list stay small, or is it expected to grow to millions of records? Will there be lots of reads on this table? Lots of writes? Lots of updates? These are all factors that need to be considered when deciding how to store collections of data.
Also, Key/Value data stores, Document stores such as Cassandra, MongoDB, Redis etc provide a good solution as well. Just be aware of where the data is actually being stored (if its being stored on disk or in memory). Not all of your data needs to be in the same database. Some data does not map well to a relational database and you may have reasons for storing it elsewhere, or you may want to use an in-memory key:value database as a hot-cache for data stored on disk somewhere or as an ephemeral storage for things like sessions.
A sidenote to consider, you can store arrays in Postgres.
In MySQL, use the JSON type.
Contra the answers above, the SQL standard has included array types for almost twenty years; they are useful, even if MySQL has not implemented them.
In your example, however, you'll likely want to create three tables: person and fruit, then person_fruit to join them.
DROP TABLE IF EXISTS person_fruit;
DROP TABLE IF EXISTS person;
DROP TABLE IF EXISTS fruit;
CREATE TABLE person (
person_id INT NOT NULL AUTO_INCREMENT,
person_name VARCHAR(1000) NOT NULL,
PRIMARY KEY (person_id)
);
CREATE TABLE fruit (
fruit_id INT NOT NULL AUTO_INCREMENT,
fruit_name VARCHAR(1000) NOT NULL,
fruit_color VARCHAR(1000) NOT NULL,
fruit_price INT NOT NULL,
PRIMARY KEY (fruit_id)
);
CREATE TABLE person_fruit (
pf_id INT NOT NULL AUTO_INCREMENT,
pf_person INT NOT NULL,
pf_fruit INT NOT NULL,
PRIMARY KEY (pf_id),
FOREIGN KEY (pf_person) REFERENCES person (person_id),
FOREIGN KEY (pf_fruit) REFERENCES fruit (fruit_id)
);
INSERT INTO person (person_name)
VALUES
('John'),
('Mary'),
('John'); -- again
INSERT INTO fruit (fruit_name, fruit_color, fruit_price)
VALUES
('apple', 'red', 1),
('orange', 'orange', 2),
('pineapple', 'yellow', 3);
INSERT INTO person_fruit (pf_person, pf_fruit)
VALUES
(1, 1),
(1, 2),
(2, 2),
(2, 3),
(3, 1),
(3, 2),
(3, 3);
If you wish to associate the person with an array of fruits, you can do so with a view:
DROP VIEW IF EXISTS person_fruit_summary;
CREATE VIEW person_fruit_summary AS
SELECT
person_id AS pfs_person_id,
max(person_name) AS pfs_person_name,
cast(concat('[', group_concat(json_quote(fruit_name) ORDER BY fruit_name SEPARATOR ','), ']') as json) AS pfs_fruit_name_array
FROM
person
INNER JOIN person_fruit
ON person.person_id = person_fruit.pf_person
INNER JOIN fruit
ON person_fruit.pf_fruit = fruit.fruit_id
GROUP BY
person_id;
The view shows the following data:
+---------------+-----------------+----------------------------------+
| pfs_person_id | pfs_person_name | pfs_fruit_name_array |
+---------------+-----------------+----------------------------------+
| 1 | John | ["apple", "orange"] |
| 2 | Mary | ["orange", "pineapple"] |
| 3 | John | ["apple", "orange", "pineapple"] |
+---------------+-----------------+----------------------------------+
In 5.7.22, you'll want to use JSON_ARRAYAGG, rather than hack the array together from a string.
Use database field type BLOB to store arrays.
Ref: http://us.php.net/manual/en/function.serialize.php
Return Values
Returns a string containing a byte-stream representation of value that
can be stored anywhere.
Note that this is a binary string which may include null bytes, and
needs to be stored and handled as such. For example, serialize()
output should generally be stored in a BLOB field in a database,
rather than a CHAR or TEXT field.
you can store your array using group_Concat like that
INSERT into Table1 (fruits) (SELECT GROUP_CONCAT(fruit_name) from table2)
WHERE ..... //your clause here
HERE an example in fiddle
I want to create a automaprimary key(auto-increment) which is start with JTM0605160001. Here
JTM: would be constant
060516: date in ddmmyy format (06-day 05-month 16-year
0001 would be iterate
So when the user want to input the data, there is already have a number series in that form. so it will be easy for me to check their data only based on the form's series number. so can you help me with some tutorial and coding?
I am using XAMPP control panel and Dreamweaver cs6.
I want serial number like this:
JTM0605160001
JTM0605160002
JTM0705160003
...
so the form will be like this:
no series : JTM0605160001 (automatic provided when user want to fill the form)
name : sally (user will fill this form)
age : 34 (user will fill this form)
table schema:
CREATE TABLE combinedKey (
id INT(4) UNSIGNED ZEROFILL NOT NULL AUTO_INCREMENT,
prefix VARCHAR(3) NOT NULL,
datePrefix VARCHAR(6) NOT NULL,
PRIMARY KEY (id, prefix, datePrefix),
age INT(3),
name VARCHAR(30)
);
So, we combine three columns to a primary key consisting of your auto-incrementing id (note the ZEROFILL for the leading zeros), your constant prefix and the date prefix (your format is not a default date format, so we format it on INSERT, see below), based on INSERT-date.
An insert could look like this:
INSERT INTO combinedKey (`prefix`,`datePrefix`,`age`,`name`) VALUES ('JTM',DATE_FORMAT(NOW(),'%d%m%y'),34,'Sally' );
A select statement with output of series number
SELECT CONCAT(`prefix`,`datePrefix`,`id`) AS series, `name`, `age` FROM combinedKey;
+---------------+-------+------+
| series | name | age |
+---------------+-------+------+
| JTM0106160001 | Sally | 34 |
+---------------+-------+------+
1 row in set (0.00 sec)
If you need the new series number before inserting name, age, etc. you could insert with dummy data/null, store the inserted row/new series number, and UPDATE afterwards.
I am trying to build a website that it will harvest user's info and store them into a table. Lets name the table user_details. It will have the columns listed below:
id,country,city,name,surname,birthday,gender,email,password,phone_number,search_phone_number
id = 1,2,3,4.. INT AUTO_INCREMENT NOT NULL UNSIGNED PRIMARY KEY
phone_number= its unique but only in the same country. Maybe a person from UK will have the same phone_number with a person from Spain but not in UK. In other words its country-related. To make it unique the search_phone_number will be consisted of country+phone_number, ex: SPAIN394221234.
Users are going to search for other users using their unique search_phone_number.
Is there a need to try and normalize this table?
Also in the same website, i have built a simple PM system, and a gallery (showing the pictures the user uploaded). So i have 2 tables:
1)message table (sender, reiceiver,message,....)
2)photos table (directory, filename, ...)
Again, is there a need to normalize the message and photos tables?
I am a little bit confused, because in some occasions normalization is a must, but in some other its not.
Thanks in advance!
1 - create a new country table like ...
create table country (id int auto_incremenet primary key, country varchar(100));
2 - create a new city table like ...
create city (id int auto_increment primary key , city varchar(100), fk_country_id int);
fk_country_id will have the id of the country that city is located in
3 - in your table mentioned above, remove the country and city columns and add only fk_city_id column. fk_city_id will have the id of the city that person is located in
4 - create table for phones like
create table user_phones(id int auto_increment primary key, fk_country_id int, phone_number varchar(15)) ;
5 - add unique index to that table like so ..
CREATE UNIQUE INDEX idx_country_phone ON user_phones(fk_country_id, phone_number);
remove phone number and search_phone_number from your table and add fk_user_phones_id column to your table.. it will have the id value of relevant row from user_phones table
6 - when user is doing a search, filter by country id and and the phone number
I'm creating a messaging system (using PHP) and want to assign an ID number to each message (aside from each actual message having an unique ID number)...however, if someone replies to a message then i want to be able to give that message the same ID as the message being replied to...then of course I can disply them by time and show them in order.
So, if i give the field an auto_increment type is that able to be overwritten?
Meaning...each new message has auto value e.g. 1, 2, 3 etc but someone replies to number 2 so it's ID needs to also 2
Or is there a better way to do this?
Absolutely nothing prevents you from assigning any arbitrary value to an AUTO_INCREMENT column. If necessary, the table counter will adjust accordingly.
However, you cannot set as AUTO_INCREMENT a column that's not unique.
Honestly, I can't understand your design. A typical messaging system would look like this:
message_id in_reply_to
========== ===========
1 NULL
2 NULL
3 1
4 NULL
5 1
6 3
7 NULL
Duplicating IDs kind of beats the purpose of using IDs.
Update #1: OMG, it seems that it can actually be done under certain circumstances:
For MyISAM tables you can specify AUTO_INCREMENT on a secondary column
in a multiple-column index. In this case, the generated value for the
AUTO_INCREMENT column is calculated as MAX(auto_increment_column) + 1
WHERE prefix=given-prefix. This is useful when you want to put data
into ordered groups.
http://dev.mysql.com/doc/refman/5.5/en/example-auto-increment.html
Update #2: For the records, I've just tested it and you can use duplicate auto-incremented IDs in InnoDB tables as well:
CREATE TABLE foo (
foo_id INT(10) NOT NULL DEFAULT '0',
bar_id INT(10) NOT NULL AUTO_INCREMENT,
PRIMARY KEY (foo_id),
INDEX bar_id (bar_id)
)
ENGINE=InnoDB
No, auto_increment columns cannot occur multiple times.
I would keep each message ID unique - whether it is via auto increment or a uuid. Add an additional column to the message structure for thread_id - unique on creation, and then have all replies include this thread_id to link them together logically.
The way you would do this is have another column in your table called parent_id or something of the sort.
The original message would have a parent_id of NULL.
Then, when anyone posts a reply to a message, then the original ID of the message goes into the parent_id column of the new message. For instance:
id text parent_id created_at
============================================
1 'Lorem ipsum' null [time]
2 'Lorem ipsum' 1 [time]
3 'Lorem ipsum' 1 [time]
You could even go further and have the replies nested:
id text parent_id created_at
============================================
1 'Lorem ipsum' null [time]
2 'Lorem ipsum' 1 [time]
3 'Lorem ipsum' 2 [time]
In the latter case, you'd probably need some sort of recursive function to get all of the nested messages; the first way is simpler.
Best way to put unique id is; to add uniqid(rand()).
I have a database that's setup in the following way
id coach team event status
14 test 8,7,12,13,15 4,1,2,14,4 2
13 test 8,12,13,14,15,16 1,2,8,16,16 3
What i need to do, is search for rows where the first number in the "event" column matches the query. They are separated by commas, but it can be 1 or 2 or 3 digits. Im sure this is possible, just not sure how or where to begin.
Have you considered normalizing your database? Isn't it a pain to work with a database, in which a field may contain an arbitrary number of arbitrarily formatted values? As a side effect (haha), it will solve the problem you've described in your question.
Example database schema:
create table whatever (
id int not null auto_increment primary key,
coach varchar(64),
status int
)
create table teams (
id int not null auto_increment primary key,
name varchar(255)
)
create table events (
id int not null auto_increment primary key,
name varchar(255)
)
create table whatever_teams (
id int not null auto_increment primary key,
whatever_id int,
team_id int
)
create table whatever_events (
id int not null auto_increment primary key,
whatever_id int,
event_id int
)
I want to apologize in advance for the obvious lack of sql-injection-enabled code, that can be always found in the questions and answers under the tags "php" and "mysql".
This will select all rows where the first number in event is 1:
SELECT * FROM `tableName` WHERE event LIKE '1,%';
You'd be better of by changing your database scheme. Storing fields with lists of ids is not very handy.
Make extra tabels to make the links.
For example:
coach_team
id coach_id team_id
1 14 7
2 14 8
3 14 12
4 14 13
Than you can use queries like:
SELECT * FROM table_name WHERE id in
(SELECT coach_id FROM coach_team WHERE team_id = 1)
(This of course also applies to events.
Extra information:
http://en.wikipedia.org/wiki/Database_normalization
You could use SUBSTRING_INDEX to get the first value, something like this:
SELECT * FROM table_name WHERE SUBSTRING_INDEX( event, ',', 1 ) = 'value'
With this approach you can use a prepared statement with a placeholder for the search value. Also works fine if there is just one number in the event column, i.e. no commas present to match against.
$sql = "SELECT * FROM table_name WHERE event LIKE '" . $query . "',%'";
I strongly recommend you to change your database schema because from my experience, sooner or later, you have to change it to serve all your needs in the future. SHould do it now be4 too late