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:
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.)
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.
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.
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.