PHP/MySQL best practice generation a tracking number - tracking

I'm working on a call/bug tracking script and whats the best practice when generating unique tracking ids for each issue.
is it best to use the index in mysql
is there another format I could use
how do i handle the display format, i like to display a 6(345789) digit number.
if it goes over 6 digit, how do i start over again or how do I handle this?
or is it best to create a new field and generate the numbers?
suggestions???
thanks

If you use all six digit numbers, you must have less than 900,000 records or you will run out of unique values. There is no way around this except to use more digits or change the data type to varchar and allow alphanumeric values. If you don't think you'll ever have 900,000 records, I would use a mysql auto increment column, but set the sequence to start at the first six digit number (100000). You would create your table like this...
CREATE TABLE bugs
(
tracking_id INT UNSIGNED NOT NULL AUTO_INCREMENT = 100000,
...
)
So, the first tracking_id generated when you create a record would be 100000, then 100001 and so on. If you insert more than 899,999 records (exceeding 999,999) the number of digits will increase to 7 though.

Related

Best way to store thousands of numbers in SQL?

I have about 250 products and they all come with 52 weeks of history + 52 weeks of forecasts. I need to store these numbers in SQL but can't figure out the best way of doing it. I've only used databases a couple of times before so my knowledge is pretty limited...
I thought about using plain text and read/write with separators. But it felt bad in so many ways and made the entire database kinda useless.
Then I thought of adding 52 columns to the table, but I read it was a bad idea.
So now I'm back to where I began and it's just a table with
[ID] [WEEK_NUMBERS] [HISTORY_NUMBERS] [FORECAST_NUMBERS]
Is this the best way of doing it?
The ~25000-30000 rows are not a problem?
You would use a table something like this:
create table ProductHistory (
ProductHistoryId int identity primary key,
ProductId int not null references Products(ProductId),
Type varchar(255) not null,
Week date not null, -- storing this as a date is a guess
Number decimal(38, 10), -- should probably be decimal, but the scale and precision might be overkill,
constraint chk_ProductHistory_type (type in ('Forecast', 'Actual')
);
This is an example. It is unclear:
Should each row have a column for Forecast and Actual, or should they be on separate rows?
How should the week be stored?
What is the right type for Number?
But the idea is the same . . . at least one row per product/week combination.

non-identity column auto increment

I'm working on a project to consolidate data (from 2 different DBs). I have created a table that contains a few columns:
MAPPING_ID int
ContentID int
ContentValue varchar(200)
For Example, when I do my 1st set of inserts against the original data source everything is good.
Mapping_ID: 53
ContentID: 53
ContentValue: Original Data 1
Mapping_ID: 54
ContentID: 54
ContentValue: Original Data 2
But when I do my second set of inserts against the another source (the data I'm trying to merge) I would like the Mapping_ID column to continue to the next number (i.e. 55,56,57...)
I looked at the row_number function but that starts at 1. Is there a way to start it at 55?
I suppose I could make that Mapping_ID column an Identity field, but turn it off during the first insert and then seed it with the max value (54) and then turn it on during the second insert.
Is there another way to accomplish this?
In SQL Server 2012+, you may use SEQUENCE objects to populate non-identity columns with autoincrement values. Plus you may use same SEQUENCE for different tables to make numeration pass-through and obtain values from sequences in SELECT and UPDATE queries.
First, create SEQUENCE:
CREATE SEQUENCE SchemaName.SequenceName
START WITH 1
INCREMENT BY 1 ;
Then, create DEFAULT constraint with values from sequence on required column:
ALTER TABLE tableName ADD CONSTRAINT constraint_unique_name DEFAULT NEXT VALUE FOR SchemaName.SequenceName FOR Mapping_ID;
There's actually a brand new way to do this kind of thing as of SQL Server 2012: the sequence object. I'm sorry I can't script out a procedure for you as I'm working in the MySQL world at present, but it's super easy to implement. The basic idea is you're maintaining a separate database object with its own seed and increment amount, but there are some caveats to bear in mind regarding their difference from traditional identity values (e.g. you can overwrite them), so make sure you do some research.
Here are a couple of articles to get you started. If you have trouble, hit me back and I'll try to work through the code with you.
https://msdn.microsoft.com/en-us/library/ff878091.aspx
https://msdn.microsoft.com/en-us/library/ff878370.aspx
Good luck!
To get row_number() to start at 55, you could just add 54 (or whatever number) to your row_number() calculation:
(row_number() over (partition by Y order by X)) + 54

How to create a smart key, which would reset its auto increment value at the end of the month

I am currently working on a project for the management of oil distribution, and i need the receipts of every bill to get stored in a database. I am thinking of building a smart key for the receipts which will contain the first 2 letters of the city, the gas station id, the auto increment number, first letter of the month and the last 2 digits of the year. So it will be somewhat like this:
"AA-3-0001-J15". What i am wondering is how to make the AI number to go back at 0001 when the month changes. Any suggestions?
To answer the direct question - how to make the number restart at 1 at the beginning of the month.
Since it is not a simple IDENTITY column, you'll have to implement this functionality yourself.
To generate such complex value you'll have to write a user-defined function or a stored procedure. Each time you need a new value of your key to insert a new row in the table you'll call this function or execute this stored procedure.
Inside the function/stored procedure you have to make sure that it works correctly when two different sessions are trying to insert the row at the same time. One possible way to do it is to use sp_getapplock.
You didn't clarify whether the "auto increment" number is the single sequence across all cities and gas stations, or whether each city and gas station has its own sequence of numbers. Let's assume that we want to have a single sequence of numbers for all cities and gas stations within the same month. When month changes, the sequence restarts.
The procedure should be able to answer the following question when you run it: Is the row that I'm trying to insert the first row of the current month? If the generated value is the first for the current month, then the counter should be reset to 1.
One method to answer this question is to have a helper table, which would have one row for each month. One column - date, second column - last number of the sequence. Once you have such helper table your stored procedure would check: what is the current month? what is the last number generated for this month? If such number exists in the helper table, increment it in the helper table and use it to compose the key. If such number doesn't exist in the helper table, insert 1 into it and use it to compose the key.
Finally, I would not recommend to make this composite value as a primary key of the table. It is very unlikely that user requirement says "make the primary key of your table like this". It is up to you how you handle it internally, as long as accountant can see this magic set of letters and numbers next to the transaction in his report and user interface. Accountant doesn't know what a "primary key" is, but you do. And you know how to join few tables of cities, gas stations, etc. together to get the information you need from a normalized database.
Oh, by the way, sooner or later you will have more than 9999 transactions per month.
Do you want to store all that in one column? That sounds to me like a composite key over four columns...
Which could look like the following:
CREATE TABLE receipts (
CityCode VARCHAR2(2),
GasStationId NUMERIC,
AutoKey NUMERIC,
MonthCode VARCHAR2(2),
PRIMARY KEY (CityCode, GasStationId, AutoKey, MonthCode)
);
Which DBMS are you using? (MySQL, MSSQL, PostgreSQL, ...?)
If it's MySQL you could have a batch-job which runs on the month's first which executes:
ALTER TABLE tablename AUTO_INCREMENT = 1
But that logic would be on application layer instead of DB-layer...
In such cases, it is best to use a User-Defined function to generate this key and then store it. Like :
Create Function MyKeyGenerator(
#city varchar(250) = '',
#gas_station_id varchar(250) = '')
AS
/*Do stuff here
*/
My guess is , you may need another little table that keeps the last generated auto-number for the month and you may need to update it for the first record that generates during the month. For the next records, during the month, you will fetch from there and increment by 1. You can alse use a stored procedure that returns an Integer as a return code, just for the autonumber part and then do the rest in a function.
Btw, you may want to note that, using the first letter of the month has pitfalls, because two months can have the same first letter. May be try the the two-digit-numeric for the month or the first three letters of the month name.
If you ready not to insist the the AI number exactly be of identity type, you can have another table, where it is a non-identity regular integer, and then run an SQL Server Agent Task calling a stored procedure that'll do the incrementing business.

How are these tasks done in SQL?

I have a table, and there is no column which stores a field of when the record/row was added. How can I get the latest entry into this table? There would be two cases in this:
Loop through entire table and get the largest ID, if a numeric ID is being used as the identifier. But this would be very inefficient for a large table.
If a random string is being used as the identifier (which is probably very, very bad practise), then this would require more thinking (I personally have no idea other than my first point above).
If I have one field in each row of my table which is numeric, and I want to add it up to get a total (so row 1 has a field which is 3, row 2 has a field which is 7, I want to add all these up and return the total), how would this be done?
Thanks
1) If the id is incremental, "select max(id) as latest from mytable". If a random string was used, there should still be an incremental numeric primary key in addition. Add it. There is no reason not to have one, and databases are optimized to use such a primary key for relations.
2) "select sum(mynumfield) as total from mytable"
for the last thing use a SUM()
SELECT SUM(OrderPrice) AS OrderTotal FROM Orders
assuming they are all in the same column.
Your first question is a bit unclear, but if you want to know when a row was inserted (or updated), then the only way is to record the time when the insert/update occurs. Typically, you use a DEFAULT constraint for inserts and a trigger for updates.
If you want to know the maximum value (which may not necessarily be the last inserted row) then use MAX, as others have said:
SELECT MAX(SomeColumn) FROM dbo.SomeTable
If the column is indexed, MSSQL does not need to read the whole table to answer this query.
For the second question, just do this:
SELECT SUM(SomeColumn) FROM dbo.SomeTable
You might want to look into some SQL books and tutorials to pick up the basic syntax.

Generate unique ID to share with multiple tables SQL 2008

I have a couple of tables in a SQL 2008 server that I need to generate unique ID's for. I have looked at the "identity" column but the ID's really need to be unique and shared between all the tables.
So if I have say (5) five tables of the flavour "asset infrastructure" and I want to run with a unique ID between them as a combined group, I need some sort of generator that looks at all (5) five tables and issues the next ID which is not duplicated in any of those (5) five tales.
I know this could be done with some sort of stored procedure but I'm not sure how to go about it. Any ideas?
The simplest solution is to set your identity seeds and increment on each table so they never overlap.
Table 1: Seed 1, Increment 5
Table 2: Seed 2, Increment 5
Table 3: Seed 3, Increment 5
Table 4: Seed 4, Increment 5
Table 5: Seed 5, Increment 5
The identity column mod 5 will tell you which table the record is in. You will use up your identity space five times faster so make sure the datatype is big enough.
Why not use a GUID?
You could let them each have an identity that seeds from numbers far enough apart never to collide.
GUIDs would work but they're butt-ugly, and non-sequential if that's significant.
Another common technique is to have a single-column table with an identity that dispenses the next value each time you insert a record. If you need them pulling from a common sequence, it's not unlikely to be useful to have a second column indicating which table it was dispensed to.
You realize there are logical design issues with this, right?
Reading into the design a bit, it sounds like what you really need is a single table called "Asset" with an identity column, and then either:
a) 5 additional tables for the subtypes of assets, each with a foreign key to the primary key on Asset; or
b) 5 views on Asset that each select a subset of the rows and then appear (to users) like the 5 original tables you have now.
If the columns on the tables are all the same, (b) is the better choice; if they're all different, (a) is the better choice. This is a classic DB spin on the supertype / subtype relationship.
Alternately, you could do what you're talking about and recreate the IDENTITY functionality yourself with a stored proc that wraps INSERT access on all 5 tables. Note that you'll have to put a TRANSACTION around it if you want guarantees of uniqueness, and if this is a popular table, that might make it a performance bottleneck. If that's not a concern, a proc like that might take the form:
CREATE PROCEDURE InsertAsset_Table1 (
BEGIN TRANSACTION
-- SELECT MIN INTEGER NOT ALREADY USED IN ANY OF THE FIVE TABLES
-- INSERT INTO Table1 WITH THAT ID
COMMIT TRANSACTION -- or roll back on error, etc.
)
Again, SQL is highly optimized for helping you out if you choose the patterns I mention above, and NOT optimized for this kind of thing (there's overhead with creating the transaction AND you'll be issuing shared locks on all 5 tables while this process is going on). Compare that with using the PK / FK method above, where SQL Server knows exactly how to do it without locks, or the view method, where you're only inserting into 1 table.
I found this when searching on google. I am facing a simillar problem for the first time. I had the idea to have a dedicated ID table specifically to generate the IDs but I was unsure if it was something that was considered OK design. So I just wanted to say THANKS for confirmation.. it looks like it is an adequate sollution although not ideal.
I have a very simple solution. It should be good for cases when the number of tables is small:
create table T1(ID int primary key identity(1,2), rownum varchar(64))
create table T2(ID int primary key identity(2,2), rownum varchar(64))
insert into T1(rownum) values('row 1')
insert into T1(rownum) values('row 2')
insert into T1(rownum) values('row 3')
insert into T2(rownum) values('row 1')
insert into T2(rownum) values('row 2')
insert into T2(rownum) values('row 3')
select * from T1
select * from T2
drop table T1
drop table T2
This is a common problem for example when using a table of people (called PERSON singular please) and each person is categorized, for example Doctors, Patients, Employees, Nurse etc.
It makes a lot of sense to create a table for each of these people that contains thier specific category information like an employees start date and salary and a Nurses qualifications and number.
A Patient for example, may have many nurses and doctors that work on him so a many to many table that links Patient to other people in the PERSON table facilitates this nicely. In this table there should be some description of the realtionship between these people which leads us back to the categories for people.
Since a Doctor and a Patient could create the same Primary Key ID in their own tables, it becomes very useful to have a Globally unique ID or Object ID.
A good way to do this as suggested, is to have a table designated to Auto Increment the primary key. Perform an Insert on that Table first to obtain the OID, then use it for the new PERSON.
I like to go a step further. When things get ugly (some new developer gets got his hands on the database, or even worse, a really old developer, then its very useful to add more meaning to the OID.
Usually this is done programatically, not with the database engine, but if you use a BIG INT for all the Primary Key ID's then you have lots of room to prefix a number with visually identifiable sequence. For example all Doctors ID's could begin with 100, all patients with 110, all Nurses with 120.
To that I would append say a Julian date or a Unix date+time, and finally append the Auto Increment ID.
This would result in numbers like:
110,2455892,00000001
120,2455892,00000002
100,2455892,00000003
since the Julian date 100yrs from now is only 2492087, you can see that 7 digits will adequately store this value.
A BIGINT is 64-bit (8 byte) signed integer with a range of -9.22x10^18 to 9.22x10^18 ( -2^63 to 2^63 -1). Notice the exponant is 18. That's 18 digits you have to work with.
Using this design, you are limited to 100 million OID's, 999 categories of people and dates up to... well past the shelf life of your databse, but I suspect thats good enough for most solutions.
The operations required to created an OID like this are all Multiplication and Division which avoids all the gear grinding of text manipulation.
The disadvantage is that INSERTs require more than a simple TSQL statement, but the advantage is that when you are tracking down errant data or even being clever in your queries, your OID is visually telling you alot more than a random number or worse, an eyesore like GUID.