1

Here is my case:

TABLE 1: Tickets Columns (id, user_id)

TABLE 2: Ticket Choices Columns (id, ticket_id, choice_code)

So a user can't have a tickets with similar choices, e.g

TICKETS:

id user_id
1 john
2 mary

Ticket Choices:

id ticket_id choice_code
1 1 abc
2 1 xyz

Would be allowed, but repeating the same entries for the same user/ticket owner should be considered invalid. But if the entries belong to a ticket that belongs to a different user, they should be accepted.

I have been able to do this on an application level with some validation, by querying the db first, then checking submitted data against the results.

Now, I want this to be enforced on the database level. I have read about check constraints but from my findings, when multiple tables/joins are to be used, they don't apply. Can something like this be enforced?

EDIT: More examples

Tickets:

  1. PK: 100, user: John
  2. PK: 102, user: John
  3. PK: 103, user: Mary

Ticket Choices.

  1. PK: 200, Ticket FK: 100, Choice Code: ABC

  2. PK: 201, Ticket FK: 100, Choice Code: JFK

  3. PK: 202, Ticket FK: 102, Choice Code: ABC

  4. PK: 203, Ticket FK: 103, Choice Code: ABC

  5. PK: 204, Ticket FK: 103, Choice Code: JFK

The following entries/should not be accepted once the above entries have been commited:

Ticket:

  1. PK: 104, user: John
  2. PK: 105, user: Mary

Ticket Choices.

  1. PK: 205, Ticket FK: 104, Choice Code: ABC // Because a ticket choices set for John with {ABC} already exists

  2. PK: 206, Ticket FK: 105, Choice Code: ABC

  3. PK: 207, Ticket FK: 105, Choice Code: JFK

The last two because User Mary has a ticket with choice set {ABC, JFK} already.

4
  • Thanks for the clarification... by this logic, shouldn't ticket choices id 202 have failed because John/ABC already exists? Commented Mar 16, 2021 at 8:41
  • No, because 202 belongs to a different ticket, 102. So first ticket set for ticket 100 = {ABC, JFK} and second set, ticket 102 = {ABC}, so by the rules I'm trying to establish this user, John, doesn't have duplicate sets. Commented Mar 16, 2021 at 10:53
  • I think I've failed this test... Wubba lub dub Commented Mar 16, 2021 at 10:57
  • 1
    I appreciate your input though! Might have to consider denormalizing the choices table as you suggested....Gubba nub nub doo rah kah. Commented Mar 16, 2021 at 11:00

1 Answer 1

1

I think you want a unique constraint:

alter table ticket_choices
add constraint ticket_choices_u1 unique (ticket_id, choice_code)

These will run fine:

insert into ticket_choices values (1, 1, 'abc');
insert into ticket_choices values (2, 1, 'xyz');

This will throw an error:

insert into ticket_choices values (3, 1, 'abc');

SQL Error [23505]: ERROR: duplicate key value violates unique constraint "ticket_choices_u1" Detail: Key (ticket_id, choice_code)=(1, abc) already exists.

You can only have one PK, but a unique constraint can be different from the PK.

-- EDIT --

I can't imagine this is particular efficient, and I am hopeful there is a better way to do it, but I'm guessing you can implement a trigger to validate before every insert.

CREATE FUNCTION ticket_choices_insert()
  RETURNS trigger
  LANGUAGE plpgsql
AS $BODY$
DECLARE
  ticket_please integer;
BEGIN

  select count (*)
  into ticket_please
  from ticket_choices tc
  join tickets t on tc.ticket_id = t.id
  join tickets t2 on t.user_id = t2.user_id
  where tc.choice_code = NEW.choice_code and t2.id = NEW.ticket_id;
  
  if ticket_please > 0 then
    return null;
  else
    return NEW;
  end if;
  
END;
$BODY$;

CREATE TRIGGER ticket_choices_insert_trigger
BEFORE INSERT ON ticket_choices
FOR EACH ROW EXECUTE PROCEDURE ticket_choices_insert();

I wonder if a better option might be to denormalize the ticket_choices table and just add the user_id as a derived field. Then it seems the unique constraint would work out of the box.

Sign up to request clarification or add additional context in comments.

3 Comments

But the second option/entry should be accepted, because: first set => [abc, xyz] second set: => [xyz] these are all unique according to what I want. But repeating the same set for a user, it should then throw an error.
Oops, sorry. Can you give a sample row that you want to throw the exception?
I have put more examples on the question

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.