1

I have the following fields in my table:

id - user_id - display_time - icon_id - background_id - page_name - template_id - sort_id - time

Basically, each user has their own slides that they can create and these are just some settings within it. These are for the custom slides but each user will have 12 or so default slides that are pre-made.

My question is.. for the pre-made slides that all users get, I don't need to define all of those fields. It will already have a background and icon and all of that, that cannot be changed. However it needs to be on this table because the user can still change the sort order and the time.

So... I could define the background and icon for each pre-made slide, but in the future if I did want to change the background of the universal "Dashboard" page then there is no easy way to make the change, since it is already in the database for that background_id.

Sorry if that was really confusing. Does anyone have any suggestions on how to approach this? I hope I have the right idea here.


So this table is good for the custom slides but I need to fit the universal pages that all users get in here so they can define some important variables like how long the slide will show for and the order. Is there an easier way to do this?

Edit:

I need to have the ability to add more than 1 of the same slide in the sort order. So if someone wants slide 1 to show up again and just change the sort order and display time. So they can have many different "instances" of each slide.

Can I take out the slide_id PRIMARY key without it messing anything up? It says it is Unique right now which I think is making this mess up if I try to add another of the same slide.

Thanks!

enter image description here

Drew
  • 6,736
  • 17
  • 64
  • 96

3 Answers3

3

This is similar to the answer given by @Freeman Latif. Showing the table definitions may make it more clear where the sort and display attributes belong: these attributes belong in the table that associates users to their slide choices.

I'm making some guesses about how you flexible you want these attributes to be. So my apologies if you have different intentions for the attributes than my design supports.

For instance, I'm adding a Templates table so that you can define a default icon & background and then apply that design as a default to the slides. Then if you ever change the default background, you only need to change it in one row in the Templates table instead of many rows in the Slides table. That's part of the benefit of normalization: a fact like the background is only recorded in just one place, so you don't accidentally change it on some rows and not other rows.

CREATE TABLE Templates (
    template_id      INT PRIMARY KEY,
    icon_id          INT,
    background_id    INT
);

CREATE TABLE Slides (
  slide_id           INT PRIMARY KEY,
  template_id        INT,
  page_name          VARCHAR(20),
  FOREIGN KEY (template_id) REFERENCES SlideTemplates(template_id)
);

CREATE TABLE SlideCustom (
  slide_id           INT PRIMARY KEY,
  icon_id            INT,
  background_id      INT,
  FOREIGN KEY (slide_id) REFERENCES Slides(slide_id)
);

Note that slide_id is both a foreign key referencing Slides, and also the primary key of SlideCustom. So it has a 1:1 relationship to that table.

A given user's slide choices include the choice of slide, whether it is a default slide or a custom slide, and the user's choice for sort order and display time. Therefore multiple users can choose a given slide, but each user can have a different choice for sort and display of that slide.

CREATE TABLE UserSlides (
  user_id            INT NOT NULL,
  slide_id           INT NOT NULL,
  sort_order         INT NOT NULL,
  display_tenths_sec INT NOT NULL DEFAULT 10,
  PRIMARY KEY (user_id, slide_id),
  FOREIGN KEY (user_id) REFERENCES Users(user_id),
  FOREIGN KEY (slide_id) REFERENCES Slides(slide_id)
);

Now you can get every slide for a user and the slide's icon and background, whether it's default or custom:

SELECT u.user_id, u.display_tenth_sec,
  COALESCE(c.icon_id, t.icon_id) AS icon_id,
  COALESCE(c.background_id, t.background_id) AS background_id,
FROM UserSlides u
JOIN Slides s USING (slide_id)
LEFT OUTER JOIN SlideCustom c USING (slide_id)
LEFT OUTER JOIN Templates t USING (template_id)
WHERE u.user_id = 20860
ORDER BY u.sort_order;

Re your comment and additional requirement that a user can use a given slide more than once:

Certainly the sort order is unique for a given user. So you can make (user_id, sort_order) be the primary key, and slide_id is just another non-unique attribute:

CREATE TABLE UserSlides (
  user_id            INT NOT NULL,
  slide_id           INT NOT NULL,
  sort_order         INT NOT NULL,
  display_tenths_sec INT NOT NULL DEFAULT 10,
  PRIMARY KEY (user_id, sort_order),
  FOREIGN KEY (user_id) REFERENCES Users(user_id),
  FOREIGN KEY (slide_id) REFERENCES Slides(slide_id)
);
Bill Karwin
  • 538,548
  • 86
  • 673
  • 828
  • Thanks so much for your help. So one question: what's the point of the templates table? and it seems like the Slides table can have the same exact fields as the SlideCustom because it also needs a page_name and can just define the background and icon from there. right? – Drew Dec 24 '11 at 22:33
  • no problem, I was just curious! because the slides table will have the 12 default slides only and that's it, right? so if I do change the default background it would still be just one place not many. or am I missing something? – Drew Dec 24 '11 at 23:16
  • No -- the Slides table will have all the slides, both default and custom. That's so the UserSlides can reference all the user's slides using a foreign key, and order them. The custom slides have one row in Slides and one row in SlideCustom. – Bill Karwin Dec 24 '11 at 23:24
  • Ohhh I understand now. Thanks again I'll let you know if I have any other questions when I put it all together. – Drew Dec 24 '11 at 23:28
  • Sorry to be a pain but if Custom slides need to also have a row in the Slide table then that means it has to have a template_id. But the icon and background will be defined in the custom_slides table so what would I do for the template_id? The templates should only be for the default slides – Drew Dec 25 '11 at 18:08
  • You can leave the template_id NULL in some rows in the Slides table. – Bill Karwin Dec 25 '11 at 21:48
  • Okay and i'm not familiar with COALESCE so instead of displaying background_id I want to pull the background name from the slide_backgrounds table. I have the following: INNER JOIN slide_backgrounds ON t.background_id = slide_backgrounds.background_id - so I can get the value with slide_backgrounds.name but how do I tie that in with the COALESCE? – Drew Dec 26 '11 at 03:40
  • COALESCE is an SQL function that returns its first non-NULL argument. For a custom slide, c.background_id will be non-NULL, otherwise it'll be a default slide and c.backgorund_id will be NULL, so it'll default to t.background_id. If you want, you can join `ON COALESCE(c.background_id, t.background_id) = slide_backgrounds.background_id`. – Bill Karwin Dec 26 '11 at 07:28
  • Thank you! I went on your profile and saw your SQL book you created. Would you recommend that for me? – Drew Dec 26 '11 at 14:01
  • Of course! :-) I wrote it specifically for developers who find themselves needing to use SQL databases, but without formal training. I hope the book can save folks like you a lot of time, by showing you the most common mistakes that I see on Q&A groups like this one. It's not intended to be an introduction to SQL, though. – Bill Karwin Dec 26 '11 at 18:26
  • Hey Bill, so one of my templates does not have a page name or an icon, so it is kind of a unique layout. So I tried to make those two fields NULL when adding the template but then the slide will not show because COALESCE only shows NOT NULL fields. Is there anything I can do? – Drew Dec 30 '11 at 14:50
  • That's wrong. COALESCE accepts NULL arguments, and if it has only NULL arguments, it returns NULL. – Bill Karwin Dec 30 '11 at 16:56
  • I filled in everything except for icon_id and page_name and left those two NULL and the slide will not show in my query. When I fill both of those in, it will then show. – Drew Dec 30 '11 at 16:57
  • Aha, I understand what you're doing now. Any join against NULL will fail to match. So if you're using COALESCE in a join condition as we discussed above, and neither c nor t has a non-null value, it won't work. – Bill Karwin Dec 30 '11 at 17:35
  • OK and one more question (sorry) I edited my post above to include the question with a screen shot. – Drew Dec 30 '11 at 21:36
0

You can separate this table into 3 different tables: 1 for the default slides that will never change (this should have 12 rows for the 12 default slides), 1 for the rest of the informations which are dynamic (sort time, time), 1 for the "custom" slides that the user made. The 3 tables should be connected by the slide_id. Then use INNER JOIN and UNION to display the tables together.

Freeman
  • 1,201
  • 1
  • 11
  • 20
  • but the default slides need a user_id attached to it, so it can determine the sort id and time for that particular user, right? so i'm a little confused. – Drew Dec 24 '11 at 01:35
0

First of all, "id" is a little ambiguous, so I'd rename that to "slide_id".

For the default slides, you could add a "default_slide" column (with a value of 0 for not and 1 indicating "default"). This way you could have your default slides in the same table as the other slides, but you could easily code your application to not allow those slides to be updated. You could accomplish the same thing with a check constraint or trigger, but I'm a believer in keeping business logic in the application (not the database).

Also, you'll want to split-out "user_id" from this table into a bridge table that looks like this:

table: user_slides
user_id int
slide_id int

This way, you only need to define the rows for the default slides once, but many users can have access to them.

Aaron
  • 55,518
  • 11
  • 116
  • 132