What kind of data to use for sale ID

Asked

Viewed 1,202 times

3

I have a Windows Form application developed in C# and with SQL database.

One of the functions of the system is to carry out SALE for several different COMPANIES and in several different POS (point of sale), however, using a single database. I use ID to control the sale it is bigint AUTO_INCREMENT in the database.

Problem: Company 1 makes sale 1, 3, and 5 company 2 makes sale 2, 4, 6 the customer thinks the system is wrong because, is not following a sequential sale order.

Then I thought about putting Co. Company + Sales Number.

However, the company is recorded in the same client table so I can easily a company with the code 9000 and I can have a sale with the code 10000 I’m afraid of then this field blind. What kind of data could I use to prevent this?

Problem 2: I have a registered company 1 and 11 the system can be lost when making the sale when company 1 makes the sale 11 or when company 11 makes the sale 1.

How I could solve this problem?

4 answers

5


Different data

The problem is you’re mixing something internal to the system with something external to the system. It’s even possible to do this, but the application has to work by treating this.

The right thing to do is to do what you’re doing for your internal control, so there’s a ID auto incremented by database. Probably a BIGINT is too big for what you need, but you can leave it if you think you should.

This is called replacement key and is the most common to do.

To show the user there will be another sequential numbering control. Need to have a control table of this per company and need access and increment in atomic operation not to create duplicity.

Composite key

If you don’t want to use a replacement key, use the ID of the enterprise in a column and the ID from the sale in another column and make the table primary key be composed by the two columns together. So you can use a unique non-repeating identifier that serves internal use and meets the external requirement.

I hope a future requirement does not create problems in using this.

Single key

You can still do a column with both IDs, but then I think it would be better to use a type CHAR. No sense putting two numbers together the way you’re thinking. Using text is not ideal, but creating a number by joining digits is completely wrong. I put as alternative, but it is not a good solution in general. I just do not rule out.

  • Bigown, if I use the composite key I will not have this problem: I have a registered company 1 and 11 the system may get lost while performing the sale when Company 1 makes the sale 11 or when Company 11 makes the sale 1.

  • 1

    No, it does not run, company code is one thing, sale code is another. If did and occurred, did something wrong.

  • @mustache is right. This will occur if you do sums of integers, for example 11 + 1 = 12 and 1 + 11 = 12, but if you concatenate with string it is 1 & 11 = 111 and 111 & 1 = 1111. Look at my example in my answer.

  • @Murilo but I’m talking about composite key, neither sums numbers nor concatenates texts. The concatenation would occur in the third option I put and would work also.

  • @bigown, how do I do this "replacement key and it’s the most common to do. To show the user there will be another sequential numbering control. Need to have a control table of this per company and need access and increment in atomic operation not to create duplicity."

  • @Lilloh It is a process that involves several parts of the code, it is not easy to put in an answer, even worse in a comment. The answer from Cantoni shows a part of this, despite being in Groovy and I don’t know if you need to do all that. Think you have two dice. One of them the ID which I think knows how to handle, it is primary key, your system works with it. The other one is given as any other that shows to the user. Actually there are two columns, one of them is the company. I think it’s okay to do that. The other is sequential code controlled by you. There is a sequence for each company.

Show 1 more comment

2

I believe it is best to use a primary key generated by SQL itself or a C# GUID to save to the bank and add two columns, one the company code and the other the sequential number of the sale, so when you make a new sale, the key will never be the problem and Voce checks which was the last sale of the company and increments the sequential number.
As the company number and the coupon are separate columns I think Voce should not have the second problem too, since the company Voce can pick up from the logged in user or type in a separate field.

If you do not want to create individual columns or tables for each company, Oce can also use a string as a key, placing a separator between the company and the sales number "company-sale" then separating in the application.

2

First the bigint is a very large field, it is difficult to burst, has to have many sales even with company code 9000.

bigint: -2 63 (-9.223.372.036.854.775.808) to 2 63-1 (9.223.372.036.854.775.807)

https://msdn.microsoft.com/pt-br/library/ms187745.aspx

You could create a new column for the sale number. Keep the primary key as auto-increment of the database, but you do the manual increment of the sale number by making a Max + 1, display the sale number to the customer, not the code.

Even if you used one sequence you wouldn’t get the sales 11 12 13 14 for company 1, you would need a Quence for each company.

You could make a trigger that will generate the sales code, generating the code = company code + sales Qtde of this company, your codes would be like this:

Company 9000: 90001, 90002, 90003, 90004, 9000125

Company 11: 11, 12, 13, 14, 1125

CREATE TRIGGER  triggerInsertVenda ON tbVenda
INSTEAD OF INSERT AS

SELECT * INTO #tmp FROM inserted
DECLARE @codEmpresa int = (SELECT codempresa FROM inserted)
DECLARE @count int = (SELECT COUNT(*) FROM tbVenda WHERE codEmpresa = @codEmpresa)

UPDATE #tmp SET codigo = convert(int, convert(varchar, @codEmpresa) + convert(varchar, @count + 1))


INSERT INTO tbVenda SELECT * FROM #tmp;
  • Murilo, actually I said wrong I have a table Person it is related to Customer, Supplier, Employee, Professional and Company. The Person table is the main yesterday has the information that is common to all.

  • My fear of crashing and that SQL 2012 has a bug at certain times it gets lost in auto increment by playing a number up ahead. However, if I use the solution you went through, it may not be in the way.

  • OK. I gave the example of how to deal with Trigger.

  • @Lilloh, would you have a reference to this SQL Server bug? I’d like to read about it. Murilo, Trigger’s solution solves, but having to count the tbVenda records at each sale seems to be not a good thing, especially considering the sales volume that may occur.

  • The count is instantaneous, has no significant effect, especially if you do Count(code) which is PK. High volume would be something over millions of records. This error of skipping sequence in SQL Server exists in 2012. I’ve been there. At stackoverflow in English there are topics on this.

  • http://stackoverflow.com/questions/14146148/identity-increment-is-jumping-in-sql-server-database

  • @Please see also here: https://social.msdn.microsoft.com/Forums/sqlserver/en-US/3d256650-0e94-4d0f-8b52-0ba6e1903215/primary-key-auto-incrementing-by-1000-instead-of-1?forumtransactsql &#http://stackoverflowcom.questions/14162648/sql--server-2012-column-Identity-increment-jumping-from-6-to-1000-on-7th-entry

  • Wow, a shameful bug. @Murilo, although the performance of the counting solution depends on the number of records, I still have restrictions on it, exactly because from the described, it seems that there will be a lot of transaction (in short periods of time), happening in this table, there seem to be several Pdvs. Maybe a solution that combines Trigger with what I posted in my reply will perform better, that is, to each INSERT in tbVenda Trigger would make a query in the current SEQUENCE of the COMPANY table, increment, save the value in tbVenda’s SEQ_VENDA and then update the COMPANY.

Show 3 more comments

2

If the sequential sale is something important for the user, then a viable and not very complex option is to create a field in the COMPANY table that will store in which sequence is the sale of the respective company.

If you choose this path, then it is important to increment this field in a way that only one SQL Server process can change it at a time. For this, you can do it the way below. The example is in the Groovy language, but is easily adapted to any other. The important thing is not the language, but the Sqls run to ensure that only one SQL Server process can change the SEQUENCIA field at a time (I removed this from a system where I do just that).

def incrementaSequencia(empresaId) {
      sql.execute("SET TRANSACTION ISOLATION LEVEL READ COMMITTED")
      sql.execute("BEGIN TRANSACTION")
      def rs = sql.rows("SELECT SEQUENCIA FROM EMPRESA WITH (UPDLOCK) WHERE EMPRESA_ID = :empresaId",[empresaId:empresaId])
      def sequencia = (int)rs.first().SEQUENCIA + 1
      sql.executeUpdate("UPDATE EMPRESA SET SEQUENCIA = " + sequencia + " WHERE EMPRESA_ID = :empresaId",[empresaId:empresaId])
      sql.execute("COMMIT")
      return sequencia
}

Note that in this example I need the sequence generated in my program, so I run SELECT in the above instructions. Depending on the case, just increment the field with an UPDATE. Something like this:

      sql.executeUpdate("UPDATE EMPRESA SET SEQUENCIA = SEQUENCIA + 1 WHERE EMPRESA_ID = :empresaId",[empresaId:empresaId])

Now just create a SEQ_VENDA field in the SELL table and save the generated value, IE, each sale you call the routine that generates the ID and save this value in the SEQ_VENDA field.

About the field type, I always use bigint for numerical Ids.

  • Basically I have a field in the company table that records the last sale performed correctly? In the Sale table I create a Seq_sale column and any sale I make I’m + 1 in the code of the last sale held. Then said I’m an update on the company adding +1 on last sale. That would be it???

  • Yes. You have a field in the COMPANY table that keeps the sequence of the last sale (let’s call it SEQUENCE). This is the field that should be incremented. The value of this field is what will be used in the SALE table, in a field that I named SEQ_VENDA.

  • I understood then that way I can have N sales with code 1.

  • There is how I make a lock in SQL so that company 1 has only one sale code 1?

  • Yes. The sequence is per company. Therefore, it can have repeated sequence yes (but always in different company). If you want the sequence to be unique, then you need a global counter and not per company. However, you will fall into the same problem, of sales not being in sequence.

  • This control the sequence can be repeated but in different company I have to do in the correct application?

  • As you know the COMPANY for which the sale is being made, just call this routine before recording the sale, getting the next SEQUENCE. After that, just take this amount and put in the INSERT you already make a new sale.

Show 3 more comments

Browser other questions tagged

You are not signed in. Login or sign up in order to post.