I use SQL Server. At the moment I have two tables in my Data Base.
One table is CmsContents which represents pages for my blog, the second table is called CmsImagesContents which is collecting information about images associated with a specific page.
The relationship between the two tables is of type One to Many, one page can have many images but one image can have only one page.
I understand this design is pretty straightforward and I started to realize some limitations, here my questions:
I need to add an image to my database before associating it with a page, I'm not a big fan of NULL values. What are the options available in my design?
Would you suggest my design for this scenario? Do you know a better alternative?
Thanks for your help!
CREATE TABLE [dbo].[CmsImagesContents](
[ImageContentId] [int] IDENTITY(1,1) NOT NULL,
[ContentId] [int] NOT NULL,
[RowGuid] [uniqueidentifier] NOT NULL,
[Title] [varchar](64) NOT NULL,
[AltTag] [nvarchar](256) NOT NULL,
[Caption] [nvarchar](256) NOT NULL,
[CopyrightNote] [nvarchar](256) NOT NULL,
CONSTRAINT [PK_CmsImagesContents_ImageContentId]
PRIMARY KEY CLUSTERED ([ImageContentId] ASC)
)
ALTER TABLE [dbo].[CmsImagesContents] WITH CHECK
ADD CONSTRAINT [FK_CmsImagesContents_ContentId]
FOREIGN KEY([ContentId]) REFERENCES [dbo].[CmsContents] ([ContentId])
You could create an intersecting table. If I was naming the tables they would be named
Content
--------
ContentID (PK)
Title
Text
etc...
Image
-----
ImageID (PK)
Size
Title
etc....
ContentImages
--------------
ContentImagesID (PK)
ContentID
ImageID
And now add a unique constraint on the imageID in ContentImages (so it can only appear in the intersecting)table once)
Now you can add content and images as you wish and then associate an image to content by populating the intersecting table
Related
I've got a very simple relationship between two tables that are used to manage custom UI branding:
ui_portal_branding
CREATE TABLE ui_portal_branding
(
id VARBINARY(16) NOT NULL,
branding_type VARCHAR(128) NOT NULL,
portal_name NVARCHAR(128) NOT NULL,
theme_id VARBINARY(16) NOT NULL,
portal_logo VARBINARY(16) NULL,
portal_favicon VARBINARY(16) NULL,
background_color VARCHAR(50) NULL,
organization_id VARBINARY(16) NULL,
CONSTRAINT pk_ui_port_bran_id PRIMARY KEY (id)
)
ui_portal_resource
CREATE TABLE ui_portal_resource
(
id VARBINARY(16) NOT NULL,
mime_type NVARCHAR(128) NOT NULL,
binary_data VARBINARY(MAX) NOT NULL,
CONSTRAINT pk_ui_port_reso_id PRIMARY KEY (id)
)
Branding is the main table, Resources is a BLOB store for binary data. Both portal_logo and portal_favicon in the branding table are optional binary data from the resource table.
I'd like to define this as a foreign key constraint with the following general logic: neither logo or favicon are required to be defined. If they are defined, they point to a record in the resource table by ui_portal_resource.id. If the data is deleted from the resource table, I want to set the corresponding column in the branding table to null. I don't want to disallow the resource deletion, I don't want to cascade the delete to the branding table.
So I define the following:
ALTER TABLE ui_portal_branding
ADD CONSTRAINT fk_ui_port_bran2ui_port_reso
FOREIGN KEY (portal_logo) REFERENCES ui_portal_resource (id)
ON DELETE SET NULL
So far so good. Now I define:
ALTER TABLE ui_portal_branding
ADD CONSTRAINT fk_ui_port_bran2ui_port_reso2
FOREIGN KEY (portal_favicon) REFERENCES ui_portal_resource (id)
ON DELETE SET NULL
and all of a sudden we have a problem:
Introducing FOREIGN KEY constraint 'fk_ui_port_bran2ui_port_reso2' on table 'ui_portal_branding' may cause cycles or multiple cascade paths. Specify ON DELETE NO ACTION or ON UPDATE NO ACTION, or modify other FOREIGN KEY constraints.
This to me seems wrong. I'm not introducing a cycle. It's two tables with the foreign keys defined in a single direction. I guess it can technically be multiple cascade paths–if the same resource is the favicon and the logo it has to set 2 things null. But really? This is the deal breaker for the SQL Server engine? Oracle and Postgres both find this situation to be acceptable.
Is there a sensible workaround for this issue? I'm not interested in a solution involving triggers. Is there a better way to model the data? I was hoping that the resources table could service more than just the branding table, which led to the current FK placement. But maybe that is just not possible?
I am writing application to store and retrieve stock market price data which the data is inserted on daily basis. I am storing the data for each asset (Stock) and for most of the market in the world. This is my current design of the tables
Country table:
CREATE TABLE [dbo].[List_Country]
(
[CountryId] [char](2) NOT NULL,
[Name] [nvarchar](100) NOT NULL,
[CurrenyCode] [nvarchar](5) NULL,
[CurrencyName] [nvarchar](50) NULL
CONSTRAINT [PK_dbo.List_Country]
PRIMARY KEY CLUSTERED ([CountryId] ASC)
)
Asset table:
CREATE TABLE [dbo].[List_Asset]
(
[AssetId] [int] IDENTITY(1,1) NOT NULL,
[Name] [nvarchar](max) NOT NULL,
[CountryId] [char](2) NOT NULL,
CONSTRAINT [PK_dbo.List_Asset]
PRIMARY KEY CLUSTERED ([AssetId] ASC)
)
Foreign key constraint on Country:
ALTER TABLE [dbo].[List_Asset] WITH CHECK
ADD CONSTRAINT [FK_dbo.List_Asset_dbo.List_Country_CountryId]
FOREIGN KEY([CountryId])
REFERENCES [dbo].[List_Country] ([CountryId])
ON DELETE CASCADE
GO
Stock_Price table:
CREATE TABLE [dbo].[Stock_Price_Data]
(
[StockPriceDataId] [int] IDENTITY(1,1) NOT NULL,
[AssetId] [int] NOT NULL,
[PriceDate] [datetime] NOT NULL,
[Open] [int] NOT NULL,
[High] [int] NOT NULL,
[Low] [int] NOT NULL,
[Close] [int] NOT NULL,
[Volume] [int] NOT NULL,
CONSTRAINT [PK_dbo.Stock_Price_Data]
PRIMARY KEY CLUSTERED ([StockPriceDataId] ASC)
)
Foreign key constraint on Asset:
ALTER TABLE [dbo].[Stock_Price_Data] WITH CHECK
ADD CONSTRAINT [FK_dbo.Stock_Price_Data_dbo.List_Asset_AssetId]
FOREIGN KEY([AssetId])
REFERENCES [dbo].[List_Asset] ([AssetId])
ON DELETE CASCADE
The concern I have at the moment is Stock_Price_Data table would be filled with high volume rows, i.e. For a specific market in a country, there can be easily 20,000 assets. Thus, in a year (260 days of trading) , I could potentially have 5.2 million rows for each country.
The application does not restrict a user from accessing data other than default country (which is setup during login).
Is it a good idea to have separate table (i.e. Stock_Price_Data_AU) for each country? Or is there a better way to design the database for the above scenario?
-Alan-
First of all - I'd drop the _data from the table name - its overkill.
If you are reasonably certain that the users will always filter the data by Country - ie only looking at 1 country at a time then I'd consider partitioning the table by Country ID - this way SQL Server will use partition elimination to pick only the relevant data. This way you get the ease of maintenance from 1 table but you get the performance as if it is a separate table per country. (I'm assuming you have Enterprise Edition) If your load works on a per country basis too then you can even switch out the partition and then drop the indexes to get even faster loads.
I have a table ApplicationRegion in a one-to-many relationship to Translation.
I want to set FK's from Translation.appname/isocode to ApplicationRegion.appname/isocode
But that did not work as you can see from the screenshot.
When the FK configure window opens 3 columns are shown on the left/right side
appname
isocode
resourcekey
Then I chose as parent table ApplicationRegion and removed the resource key column from the FK setting.
And clicked OK but then I got the error you see on the screenshot.
Finally I made it work with that workaround and I would like to know why I had to use this workaround?
Remove PK from Translation.ResourceKey column
Open FK configure window
Only 2 columns appear now as foreign keys
I click OK
Now I add the PK again to Translation.ResouceKey column
I added test data to all 3 tables and everything is fine.
WHY this workaround?
UPDATE
HAHA...
I think you must have hit a weird glitch in SSMS. I was able to create your schema using SSMS 2014 without any errors. It did pre-fill the three composite primary key columns when adding the new FK. I was careful to make sure they were all blanked out before I started to add the two columns in the FK. Maybe SSMS thought one of the blank rows still had data in it.
Edit: Just had one more thought, SSMS is know for caching any changes that are made when editing a table. For example, if you go to modify two tables and have both edit windows open. Then you change the PK in one window and then try to reference it in the second window, it will error because it has cached what the schema was for the first table when the window was first opened.
Here is my generated DDL:
CREATE TABLE [dbo].[AppRegion](
[appname] [nvarchar](50) NOT NULL,
[isocode] [char](5) NOT NULL,
CONSTRAINT [PK_AppRegion] PRIMARY KEY CLUSTERED
(
[appname] ASC,
[isocode] ASC
)
) ON [PRIMARY]
CREATE TABLE [dbo].[Translation](
[ResourceKey] [nvarchar](128) NOT NULL,
[appname] [nvarchar](50) NOT NULL,
[isocode] [char](5) NOT NULL,
[text] [nvarchar](400) NULL,
CONSTRAINT [PK_Translation] PRIMARY KEY CLUSTERED
(
[ResourceKey] ASC,
[appname] ASC,
[isocode] ASC
)
) ON [PRIMARY]
ALTER TABLE [dbo].[Translation] ADD CONSTRAINT [FK_Translation_AppRegion] FOREIGN KEY([appname], [isocode])
REFERENCES [dbo].[AppRegion] ([appname], [isocode])
I just experienced a database breakdown due to sudden extradordinary data loading from disk.
I found the issue would arise when I attempted inserting into a log table with approx. 3.5 million rows. The table features an ID column set to IDENTITY, but with no indexes or unique constraints.
CREATE TABLE [dbo].[IntegrationTestLog](
[Id] [int] IDENTITY(1,1) NOT NULL,
[Ident] [varchar](50) NULL,
[Date] [datetime] NOT NULL,
[Thread] [varchar](255) NOT NULL,
[Level] [varchar](50) NOT NULL,
[Logger] [varchar](255) NOT NULL,
[Message] [varchar](max) NOT NULL,
[Exception] [varchar](max) NULL
)
Issue triggered by this line:
INSERT INTO IntegrationTestLog ([Ident],[Date],[Thread],[Level],[Logger],[Message],[Exception]) VALUES (#Ident, #log_date, #thread, #log_level, #logger, #message, #exception)
There are possibly many other queries that will trigger it, but this one I know for sure.
Bear with me, cuz' Im only guessing now, but does the identity seeding process somehow slow down if an index is missing? Could it by any slight chance fall back to doing a MAX(ID) query to get the latest entry? (Probably not). I haven't succeeded in finding any deep technical information about the subject yet. Please share if you know some litterature or links to such.
To solve the issue, we ended up truncating the table, which itself took VERY long. I also promoted ID to be primary key.
Then I read this article: Identity columns and found that truncate actually does touch the identity seed.
A truncate table (but not delete) will update the current seed to the
original seed value.
...which again only led me to be more suspecious of the identity seed.
Again I'm searching in the dark - please enlighten me on this issue if you have the insight.
I'll be keeping details of PageView counts for a specific table.
Table design is:
[IMAGE_ID] [int] IDENTITY(1,1) NOT NULL,
[IMAGE_PATH] [nvarchar](150) NOT NULL,
[CARTOON_ID] [int] NOT NULL,
[ADD_DATE] [datetime] NOT NULL,
[ADD_USER_ID] [int] NOT NULL,
[IMAGE_TEXT] [nvarchar](max) NULL
I'll be showing these images on each page and need the best way to keep the unique page view counts.
How would you do it?
Please remember that this table will have around 10000 images in short time and will a lot of activity. Updating this table on each request doesn't seem clever to me.
I guess the best way is to keep a temp table with
IMAGE_ID
IP_ADDRESS
VISIT_DATE
and a view table that keeps
IMAGE_ID
COUNTER
And batch update the view table with the details of temp table and clear the content of it periodically.