Question

I'm going to be running lotteries on my website, and hence there needs to be somewhere to store the tickets and numbers. I will definitely have a table, called tickets in which each row will have their own ticket id, their associated lottery id and all other information (like id of the user to whom it belongs).

However, my question is whether I should make another field in tickets to hold the numbers chosen on the ticket. It's not an option to create multiple fields such as number1, number2 etc, as each lottery will have different types of tickets (i.e lottery1 may ask you to choose 4 numbers, and lottery2 may ask you to choose 6).

So I can either make a new field which is either VARCHAR or TEXT to accept comma-separated ticket numbers, i.e: 1,2,3,4,5,6 or make another new table called numbers where each row would have the ticket id and number associated with it. However I'm not sure if this method is very efficient, as for just one ticket of 6 numbers, there would need to be 1 row in the tickets table, and 6 rows in the numbers table.

Which of these options is most efficient? Or is there an even better way to do it than this? Please remember that at the end of the lottery the code will need to cycle through each ticket to check if they have won - so option 2 might be too resource-hogging there.

Was it helpful?

Solution

In the following "Ticket[Number]" should be taken to mean "Selected Set of Lottery Numbers". Remember that Set(a,b,c) is equal to Set(c,b,a).


I would have it like this:

Purchase
  -PersonID // associate Person (one person can have many purchases)
  -TicketID // associate Ticket (a purchase is for one "ticket",
            //                   which can be purchased many times)
  -DisplayTicketNumber // for Human Display

Ticket
  -TicketNumber

That is, Purchase:M-1:Ticket

The DisplayTicketNumber is the number, as the user selected it, e.g. "3,1,2" while, on the other hand, the TicketNumber is the normalized ticket number where the small values are put first. The final form is thus min,..,max or similar. That is, any number of DisplayTicketNumbers that have the same set of values (in any order) will have the same TicketNumber:

DisplayTicketNumber  TicketNumber
1,2,3                1,2,3
2,3,1                1,2,3
3,2,1                1,2,3
3,2,1,4              1,2,3,4 .. and etc

Then put an index on TicketNumber so what a simple WHERE TicketNumber = @normalizedTicketNumber will be a very fast index.

I would actually argue this is an acceptably normalized design and the TicketNumber (along with say a Raffle number) forms a Key. My arguments for this are thus:

  1. A TicketNumber is an opaque value that uniquely identifies a Ticket (per Raffle). One does not need to "know the details" inside the DB model. (There might be a need in some cases, but not here.)

  2. The DisplayTicketNumber is an artifact of the users input; yet multiple DisplayTicketNumbers can represent the same TicketNumber. While this does represent possible "duplication" it is important to realize that this is a Friendly Display value that represents a list (which has more information than a set) of numbers chosen.

    1. In a case like this I would make the DisplayTicketNumber (and TicketNumber) immutable with triggers so that, after creation, no database inconsistencies can be introduced here.

    2. If a FK can be computed then the constraint between DisplayTicketNumber and TicketNumber can be enforced without immutability.

(I have omitted various details like having different TicketNumbers for different Raffles, etc. I also show a TicketId for a FK, but I also hinted that RaffleId,TicketNumber is an acceptable [non-surrogate] Key.)

Also, the Ticket table could be eliminated: since very few Lottery Number Sets will be shared so, if there is no extra associated Ticket information, then removing it might be an acceptable denormalization. One advantage of this is then the TicketNumber could be moved into the Purchase table and then turned into a computed column (which is still indexed) that normalized the Ticket value.

And, if MySQL allows using a computed column in a FK then using the relationship PK(Ticket.TicketNumber) -> FK(Purchase.TicketNumber), where Purchase.TicketNumber is computed, could be used to increase model integrity without eliminating the Ticket table. (I do not use MySQL, however, so I cannot say if this is viable or not.)

Happy coding.

OTHER TIPS

I'd use the second option where you make the new table, called numbers, and you have the numbers associated with it.

But I'd also add a field in the tickets table, where you indicate the amount of numbers that can be selected, and a condition where you check if the amount of numbers inserted using that ticket (using COUNT in a query) is less than the amount of numbers that can be selected, then insert.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top