-2

I wrote the count code below with the aim of having it produce auto-serial numbers for my data in place of the MySQL serial number which goes once the row is deleted. But when I run it, I observed no entries where made to the MySQL table. I later changed the codes to Dreamweaver Insert Record and there I observed that the SN (Serial Number) fields needed not to be NULL.

By asking me to enter value to the SN field before posting it means this line code: "$query=......" and "$sn=......" will not generate the values expected of it.

So in principle I need help on how to generate an auto serial number from 1 to as many datas as will be created.

<?php
if(isset($_POST['submit']))
{
    $query  = mysql_query("SELECT COUNT(*) as counter FROM tbl_donors");
    $sn     = mysql_num_rows($query) + 1;
    $donorname      = $_POST['donorname'];
    $designation    = $_POST['designation'];
    $address        = $_POST['address'];
    $city       = $_POST['city'];
    $state      = $_POST['state'];
    $country        = $_POST['country'];
    $phone      = $_POST['phone'];
    $emailaddr      = $_POST['emailaddr'];
    $user_name      = $_POST['user_name'];

    mysql_select_db ($database_xxxxxxxxxx,$xxxxxxxxxx);
   $query = ("INSERT INTO tbl_donors (donor_id, sn, donorname, designation, address , city, state, country , phone, emailaddr, user_name) VALUES ('', '$sn', '$donorname' , '$designation', '$address', '$city' , '$state', '$country', '$phone, '$emailaddr', '$user_name')");
    $results = mysql_query($query,$xxxxxxxxxx) or die
    ("Could not execute query : $query." . mysql_error());
    mysql_close();
}  
?>
Joel
  • 4,732
  • 9
  • 39
  • 54
Prince Michael
  • 85
  • 3
  • 3
  • 10
  • isn't that what auto_increment is for? http://dev.mysql.com/doc/refman/5.0/en/example-auto-increment.html – Richard Chambers Mar 03 '14 at 23:16
  • I don't understand the principe of that code? You are looking for an auto-incremental id, aren't you…… ? – Allan Stepps Mar 03 '14 at 23:17
  • Not sure I follow, but `$sn=$query['counter']+1;` ? – JBES Mar 03 '14 at 23:21
  • @Benjamin Gruenbaum: Yes its a new code. Sorry for the late response – Prince Michael Mar 04 '14 at 10:29
  • [**Please, don't use `mysql_*` functions in new code**](http://bit.ly/phpmsql). They are no longer maintained [and are officially deprecated](http://j.mp/XqV7Lp). See the [**red box**](http://j.mp/Te9zIL)? Learn about [*prepared statements*](http://j.mp/T9hLWi) instead, and use [PDO](http://php.net/pdo) or [MySQLi](http://php.net/mysqli) - [this article](http://j.mp/QEx8IB) will help you decide which. If you choose PDO, [here is a good tutorial](http://j.mp/PoWehJ). – Benjamin Gruenbaum Mar 04 '14 at 10:44
  • @Benjamin Gruenbaum: Thank you but my Anti-Virus is blocking the prepared statements page you sent. It sees the link s a something else. Can you send the actual link please – Prince Michael Mar 04 '14 at 10:51
  • Sure http://en.wikipedia.org/wiki/Prepared_statement – Benjamin Gruenbaum Mar 04 '14 at 10:52
  • @Benjamin Gruenbaum: So how can I then define the "$query" in the statement $query = mysql_query("SELECT COUNT(*) as counter FROM tbl_donors");? What will I use to replace "mysql_query" ? – Prince Michael Mar 04 '14 at 10:57
  • MySQLi or PDO, see the links above. – Benjamin Gruenbaum Mar 04 '14 at 12:03

2 Answers2

2

You need to configure your MySQL table so that the sn column has AUTO_INCREMENT enabled. Consider this example from the MySQL 5.0 Reference on AUTO_INCREMENT:

CREATE TABLE animals (
 id MEDIUMINT NOT NULL AUTO_INCREMENT,
 name CHAR(30) NOT NULL,
 PRIMARY KEY (id)
) ENGINE=MyISAM;

INSERT INTO animals (name) VALUES
 ('dog'),('cat'),('penguin'),
 ('lax'),('whale'),('ostrich');

SELECT * FROM animals;

Returns:

+----+---------+
| id | name    |
+----+---------+
|  1 | dog     |
|  2 | cat     |
|  3 | penguin |
|  4 | lax     |
|  5 | whale   |
|  6 | ostrich |
+----+---------+

In this example, nothing was passed as id, but the result was automatically generated.

You should define something link this for the sn column in your table.

Edit: Assuming you absolutely must feel like you have an additional, offset, incrementing column, one option is to make it appear so when you query the table. In the example above, let's say we want an additional column, sn, and that the difference between id and sn is 7. We could do the following:

SELECT *, (`id` + 7) as `sn` FROM animals;

Returns:

+----+---------+----+
| id | name    | sn |
+----+---------+----+
|  1 | dog     |  8 |
|  2 | cat     |  9 |
|  3 | penguin | 10 |
|  4 | lax     | 11 |
|  5 | whale   | 12 |
|  6 | ostrich | 13 |
+----+---------+----+

Note that although you can use sn in JOINs and other statements, you won't be able to use it as a foreign key in other tables.

Philippe Signoret
  • 13,299
  • 1
  • 40
  • 58
  • Thank you for your response. I already have a MySQL auto-increament field for the table. I need this one to help keep the serial number in order as the rows on the table will be deleted any time and when that happens, the figures will beginto skip. View one of the pages that need this feature by clicking this link http://netdataflow.com/rbme/donors.php . The logins you need are provided on the page. – Prince Michael Mar 04 '14 at 10:39
  • Also note that in MySQL each table can have only one auto increment field. – Prince Michael Mar 04 '14 at 10:46
  • If the link I wrote fails to open, pls use this http://www.netdataflow.com/rbme/donors.php – Prince Michael Mar 04 '14 at 10:47
  • Pls have you used MyISAM before? It seems it can be of help for what I need since the auto numbers can be used again. Please read this and advice http://dev.mysql.com/doc/refman/5.5/en/example-auto-increment.html. I am currently using InnoDB – Prince Michael Mar 04 '14 at 11:17
  • If you already have an `auto_increment` field in your table, any additional "auto_increment" field is simply a fixed value + the `auto_increment`ed field. Rather than keep track of two offset, incrementing fields, I'd explore *why* this is the case. For example, is there anything preventing `sn` to be used instead of the `donor_id`? Assuming you absolutely must have this, one option is to simply do a subsequent `UPDATE`. – Philippe Signoret Mar 04 '14 at 11:20
  • No nothing except that when a donor name is deleted, the donor_id for that row will be deleted as well e.g 1,2,3,4. If you delete row 3, it becomes 1,2,4. I want to avoid this issues as my client will worry about it as well. I want a solution that will offer continual serial order irrespective of the rows deleted. – Prince Michael Mar 04 '14 at 11:25
  • You would have this problem even if you could have two `AUTO_INCREMENT` columns. Let's say that column `donor_id` is 1, 2, 3, 4, and `sn` is 4, 5, 6, 7. When the third row deleted, you're saying you want the rows to be `(1, 4)`, `(2, 5)`, and `(4, 6)`? – Philippe Signoret Mar 04 '14 at 11:36
  • I think we are getting there now. The donor_id and sn should have same numbers, i.e. donor_id-1,2,3,4 and sn - 1,2,3,4. Now when a row say row 3 is deleted, donor_id becomes 1,2,4 while sn returns 1,2,3. This is what I want to achieve. Your last comment is close though may be because you used 4,5,6,7. Yes that is correct but I want 1,2,3 not 4,5,6 which is a continuation from where the donor_id stopped. But can InnoDB allow 2 auto_increment? – Prince Michael Mar 04 '14 at 11:56
  • In that case, what does `sn` signify? If it's liable to change like this, then you may want to consider simply not keeping it in the database at all. Consider a table with a million rows. If you delete the first row, it means you're going to have to update the 999,999 other rows so that their `sn` column is accurate. It sounds to me like this value should be something you calculate after you've obtained the data from the database. – Philippe Signoret Mar 04 '14 at 11:59
  • I see what you mean sir. So sir what do you recommend we do to resolve this? – Prince Michael Mar 04 '14 at 12:25
  • It really depends on what you need `sn` for and how you're using the MySQL database. If you only need `sn` for display purposes, then you probably have a loop somewhere iterating over the returned rows. As you iterate, keep a counter that increments and use that to display. – Philippe Signoret Mar 04 '14 at 12:27
  • This is where I have the issue. How to create the counter and insert it in my table that is shown on the web page. Can you send me a sample code on that please? – Prince Michael Mar 04 '14 at 13:04
  • First of all, you should not be using `myslq_*` functions (you should use, if anything, [`mysqli_*`](http://www.php.net/manual/en/mysqli.query.php). Second, it would be better if you showed us what you've done so far. The code you've shown is only for inserting, not for reading. – Philippe Signoret Mar 04 '14 at 13:13
  • Ok I will do that but wait, I am already using mysql_. Can I switch to mysqli_ easily without destroying my entire database? – Prince Michael Mar 04 '14 at 13:33
  • The `mysql_*` and `mysqli_*` are just functions used to access a database. They aren't the database itself, and you may switch between them without affecting the contents. – Philippe Signoret Mar 04 '14 at 13:36
  • Hi Philippe Signoret, Thank you for all your help. I tried working around but have not gotten the core result. Using this line of code "SELECT COUNT(donor_id)+1 as Counter from tbl_donors" I got the value I want which is 6+1. But now How to add to the tableset that will show all the values is where I am having a problem. I am using dreamweaver to builder my tableset. Can you help me – Prince Michael Mar 07 '14 at 02:13
0

In MySQL each table can have one and only one auto increment field. This is the correct way to generate a unique value like you have asked for each row.

http://dev.mysql.com/doc/refman/5.0/en/example-auto-increment.html

The method you have used is error prone. When you test it may work, but when it is used by multiple users it will result in duplicate ids. This is because if user and and user be request at the same time, they will both get the count at the same time, add 1 to it and then insert with the same value. Using an autoincrement field avoids this issue. It is also much faster and easier to use.

[Edit]

User asked if there was no other way to do this. There is of course otherways to do this, this however is the correct one in nearly all cases. Even if you need more than one per table, it is likely the best way to do this in MySQL is to create a second table to get another autoincrement.

That said I will propose two of the many alternatives. The crux of the problem is the need for an atomic counter, that is a counter that does not suffer from the race condition described above, and will always return the next unique id. One such source of an atomic counter is memcache. Memcache provides an atomic increment that could be used as the source for a unique id. Like all solutions this has it's downfalls, if your memcache goes down you will loose your state, and the counter will start over, thus not being so unique.

Another approach is to use MySQL locks. This can either be a table lock where in you lock the table, select the max id increment, insert and unlock the table, this requires the use of transactions as well and so will further complicate what could be very simple code. You can alternatively use MySQLs arbitrary application level locking scheme.

https://dev.mysql.com/doc/refman/5.0/en/internal-locking.html https://dev.mysql.com/doc/refman/5.0/en/miscellaneous-functions.html#function_get-lock

The complexity of implementing such an alternative is sufficient, that if you did not already know what I just explained, you should stick with autoincrement fields, they are very easy to use and fairly bullet proof.

AaronM
  • 2,339
  • 2
  • 17
  • 18
  • Is there no other way to create auto-increment besides MySQL auto-increment? – Prince Michael Mar 04 '14 at 10:44
  • There is, but it is not efficient. There are actually any number of ways to do this but any that are effective are less efficient than an autoincrement field. – AaronM Mar 05 '14 at 00:08