SQL one to many relation table design, the right way - sql

Plot: I need to book an Order which relies on 3 different type of Factory.
I have individual tables for both order and Factory. Now I need to make a one to many relations between Order and Booking Factory.
Order Table:
CREATE TABLE [dbo].[tbl_OrderInformation](
[OrderInformationId] [int] IDENTITY(1,1) NOT NULL,
[OrderId] [int] NOT NULL,
[OrderNo] [nvarchar](50) NOT NULL,
CONSTRAINT [PK_tbl_OrderInformation] PRIMARY KEY CLUSTERED
( [OrderInformationId] ASC)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE =
OFF, IGNORE_DUP_KEY = OFF,
ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]
Factory Table:
CREATE TABLE [dbo].[tbl_Factory](
[FactoryId] [int] IDENTITY(1,1) NOT NULL,
[FactoryName] [nvarchar](50) NOT NULL,
[FactoryType] [nvarchar](50) NOT NULL,
CONSTRAINT [PK_tbl_Factory] PRIMARY KEY CLUSTERED
( [FactoryId] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF,
ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]
Sample Order Data
Sample Factory Data
Now, an Order relies on multiple garments, dyeing, and printing Factory.
Suppose, Order C101 relies on Garments-A, Dyeing-A, Printing-A, Printing-B, Printing-C.
Now, I can design OrderBooking table in 2 ways.
CREATE TABLE [dbo].[tbl_OrderBooking_1](
[OrderBookingId] [INT] IDENTITY(1,1) NOT NULL,
[OrderId] [INT] NOT NULL,
[FactoryId] [INT] NULL,
[FactoryType] [NVARCHAR](50) NULL,
CONSTRAINT [PK_tbl_OrderBooking_1] PRIMARY KEY CLUSTERED
(
[OrderBookingId] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF,
ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]
This the data will look like below:
And The second way,
CREATE TABLE [dbo].[tbl_OrderBooking_2](
[OrderBookingId] [INT] IDENTITY(1,1) NOT NULL,
[OrderId] [INT] NULL,
[garmentsFactoryId] [INT] NULL,
[dyeingFactoryId] [INT] NULL,
[printingFactoryId] [INT] NULL,
CONSTRAINT [PK_tbl_OrderBooking_2] PRIMARY KEY CLUSTERED
(
[OrderBookingId] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF,
ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]
Here the data will look like,
Now, which approach of designing the OrderBooking table is more accurate and why ?
Please keep in mind that the type of factory is fixed to 3, and OrderBooking table will grow quite large over time thus tend to have heavy read and write operations.

The link table between Order & factory would be the best approach.
You will get better performance and you can create indexes on the numeric columns.
Going forward if you have any new factory then it is also each to insert without any issue.
The link table will help you to align with the Normalization rule as well. so my suggestion is go with that.

Related

Unique constraint on another column if not null

I want to create this table with the following constrains, is it possible to do with SQL Server Management Studio?
Id
ProductId [Nullable column]
CompanyId [Nullable column]
Username [unique for every productId - IF DeletedAt is not NULL]
Identifier [Nullable column] [unique for every companyId - IF DeletedAt is not NULL]
DeletedAt [Nullable column]
Update:
My table create query is the following:
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
CREATE TABLE [dbo].[User](
[Id] [int] IDENTITY(1,1) NOT NULL,
[ProductId] [int] NULL,
[CompanyId] [int] NULL,
[Username] [nvarchar](max) NOT NULL,
[Identifier] [nvarchar](max) NULL,
[DeletedAt] [datetime2](7) NULL,
CONSTRAINT [PK_User] PRIMARY KEY CLUSTERED
(
[Id] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF,
ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY] TEXTIMAGE_ON [PRIMARY]
GO
You'll want to use a unique filtered index. Here you go for the table:
/****** Object: Table [dbo].[the_table] Script Date: 7/26/2018 4:04:00 PM ******/
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
CREATE TABLE [dbo].[the_table](
[id] [int] NOT NULL,
[productid] [varchar](50) NULL,
[companyid] [varchar](50) NULL,
[username] [varchar](50) NULL,
[identifier] [varchar](50) NULL,
[deleteat] [varchar](50) NULL,
CONSTRAINT [PK_the_table] PRIMARY KEY CLUSTERED
(
[id] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]
GO
And the index for username:
SET ANSI_PADDING ON
GO
/****** Object: Index [UIDX_USERNAME] Script Date: 7/26/2018 4:03:31 PM ******/
CREATE NONCLUSTERED INDEX [UIDX_USERNAME] ON [dbo].[the_table]
(
[username] ASC
)
WHERE ([DELETEAT] IS NOT NULL)
WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, SORT_IN_TEMPDB = OFF, DROP_EXISTING = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
GO
It would be the same index logic for the other column, but I don't want to clutter this answer by posting more! I would not mess around with putting the logic in triggers or stored proc's, bad data could still sneak in. If you keep nice constraints, nobody can clutter your data up :)
You can use filtered indexes. The syntax looks like this:
create unique index unq_thetable_username on the_table(username)
where deleteAt is not null;
I don't know if you can point-and-click your way to this solution. I would just write the logic as above.
Create a unique index on ProductId and Username, and use a where clause to restrict that index to WHERE DeletedAt IS NOT NULL. Answer showing an example of a unique filtered index.
You may also need the clause AND ProductId IS NOT NULL, although that wasn't stated as a requirement, but since that column is nullable you ought to think about this.
Similar for Identifier.
You might also want to think about the value of a table where it is valid to have a row where all the columns except Id are null...

Index fragmentation SQL Server

I have problem with my indexes on two tables.
Here is code for creating the tables:
CREATE TABLE [dbo].[Table]
(
[ID] [uniqueidentifier] NOT NULL,
[IP] [nvarchar](15) NULL,
[Referrer] [nvarchar](1000) NULL,
[Domain] [nvarchar](100) NULL,
[RegID] [int] NULL,
[Agent] [nvarchar](500) NULL,
CONSTRAINT [PK_Table] PRIMARY KEY CLUSTERED
([ID] ASC)
WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF,
IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON,
ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]
GO
ALTER TABLE [dbo].[Table]
ADD CONSTRAINT [DF_Table_ID] DEFAULT (newsequentialid()) FOR [ID]
GO
And index
CREATE NONCLUSTERED INDEX [Reg_ID] ON [dbo].[Table]
(
[RegID] ASC
)
WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF,
SORT_IN_TEMPDB = OFF, DROP_EXISTING = OFF, ONLINE = OFF,
ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
And another table with index
CREATE TABLE [dbo].[Table2]
(
[Table2_ID] [int] IDENTITY(1,1) NOT NULL,
[TracID] [uniqueidentifier] NOT NULL,
[F_URL] [nvarchar](1500) NULL,
[S_URL] [nvarchar](100) NULL,
[Time] [datetime] NULL,
CONSTRAINT [PK_Table2] PRIMARY KEY CLUSTERED ([Table2_ID] ASC)
WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF,
IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON,
ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]
GO
ALTER TABLE [dbo].[Table2] WITH CHECK
ADD CONSTRAINT [FK_Table2_Table]
FOREIGN KEY([TracID]) REFERENCES [dbo].[Table] ([Web_Visitor_ID])
GO
ALTER TABLE [dbo].[Table2] CHECK CONSTRAINT [FK_Table2_Table]
GO
Index
CREATE NONCLUSTERED INDEX [IX_TracID] ON [dbo].[Table2]
(
[TracID] ASC
)
WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF,
SORT_IN_TEMPDB = OFF, DROP_EXISTING = OFF, ONLINE = OFF,
ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
In first table I have about 6M rows and in second 8M rows (a couple of thousand each day).
I have problem because indexes are fragmented up to 99% in 4 hours.
I run query (sys.columns) to get size in bytes and there are results
Table 1 Table 2
name bytes name bytes
ID 16 ID 4
IP 30 TracID 16
Referrer 2000 F_URL 3000
Domain 200 S_URL 200
RegID 4 Time 8
Agent 1000
Does anyone have some idea witch can help me to fix that fragmentation ?
Are you SURE you need to defragment? With proper hardware, fragmentation rarely matters anymore. Many old-school SQL people still recommend it, but in reality in most cases it is a relic of a past.
There are two reasons it has become irrelevant. First, all reads should be cached in RAM (if not, you need more RAM--it's cheap and will give you WAY more bang for the buck than effort spent defragmenting). Second, SSDs eliminate seeks times anyway, so fragmentation is irrelevant. As a result of these two changes, the time spent defragmenting is usually wasted.

EF 6 Bridge Table Insert Not Working

I am still trying to learn how to use EF and running into a problem with my bridge table.
When I try to create a new Order with associated Resources, I get the following SQL error:
{"Violation of PRIMARY KEY constraint 'PK_Resource_Type'. Cannot insert duplicate key in object 'dbo.Resource_Type'. The duplicate key value is (2).\r\nThe statement has been terminated."}
Code Looks like this
ResourceType resource = new ResourceType();
resource.ID = 2;
resource.Name = "Van"
order.resourceType().Add(resource)
db.Orders.Add(order);
db.SaveChanges();
Tables look like this
--Order table
CREATE TABLE [dbo].[Orders](
[Order_ID] [int] IDENTITY(1,1) NOT NULL,
[OrdernName] [varchar](100) NOT NULL,
CONSTRAINT [PK_Orders] PRIMARY KEY CLUSTERED
(
[Order_ID] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]
GO
--Resource Type table
CREATE TABLE [dbo].[Resource_Type](
[ResourceType_ID] [int] NOT NULL,
[ResourceType] [varchar] (30) NOT NULL
CONSTRAINT [PK_Resource_Type] PRIMARY KEY CLUSTERED
(
[ResourceType_ID] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]
GO
--Resource Type To Order table
CREATE TABLE [dbo].[Resource_Type_Order](
[ResourceType_ID] [int] NOT NULL,
[Order_ID] [int] NOT NULL
CONSTRAINT [PK_Resource_Type_Order] PRIMARY KEY CLUSTERED
(
[ResourceType_ID] ASC,
[Order_ID] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]
GO
ALTER TABLE [dbo].[Resource_Type_Order] WITH CHECK ADD CONSTRAINT FK_Order_Resource_Type_Order FOREIGN KEY([Order_ID])
REFERENCES [dbo].[Orders]([Order_ID])
GO
ALTER TABLE [dbo].[Resource_Type_Order] WITH CHECK ADD CONSTRAINT FK_Resource_Type_Order_Resource_Type FOREIGN KEY([ReosurceType_ID])
REFERENCES [dbo].[Resource_Type]([Resource_ID])
GO
Am I using the bridge table correctly? I want my bridge table to look like this, after I add an order (ID=1) with two resources (car ID=1 and van ID=2).

Relationships in SQL on the same table

I haven't ever really used foreign keys in my databases, I have always just written code that would enforce things for me, but I'm looking towards shifting some of that logic to the database and learning more about foreign keys.
I currently have a database which has the table Categories:
CREATE TABLE [dbo].[Categories](
[CategoryID] [bigint] IDENTITY(1,1) NOT NULL,
[ParentCategoryID] [bigint] NOT NULL,
[CategoryStatus] [bit] NOT NULL,
[CategoryTitle] [varchar](64) NOT NULL,
[CategorySlug] [varchar](64) NOT NULL,
[CategoryThumbnail] [varchar](128) NULL,
[CategoryHeaderImage] [varchar](128) NULL,
[CategoryDescription] [text] NULL,
CONSTRAINT [PK_Categories] PRIMARY KEY CLUSTERED
(
[CategoryID] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY],
CONSTRAINT [UI_Categories_Slug] UNIQUE NONCLUSTERED
(
[CategorySlug] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY] TEXTIMAGE_ON [PRIMARY]
I would like to create a foreign key that relates ParentCategoryID back up to CategoryID. When creating the FK, which would be the primary column, and which would be the foreign column in this instance?
I would think that ParentCategoryID would have to be NULLable (unless you want a top-level parent to point to itself, and that doesn't make much sense).
ALTER TABLE dbo.Categories
ADD CONSTRAINT FK_SelfParent
FOREIGN KEY (ParentCategoryID)
REFERENCES dbo.Categories(CategoryID);
True story: at a job interview at Microsoft (several years ago), a SQL Server person told me that this wasn't possible.

tsql default value dpends on other field

is something like that possible ?
CREATE TABLE [dbo].[T_ALERT](
[id] [bigint] NOT NULL IDENTITY(1,1),
[times] [int] NOT NULL DEFAULT(1),
[times left] [int] DEFAULT(times), --Here times_left get times as default
CONSTRAINT [PK_T_ALERT] PRIMARY KEY CLUSTERED
(
[user_id] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]
No, but you can accomplish the same thing by making the column TimesUsed (or whatever is appropriate for your usage) and defaulting it to 0, then just doing subtraction in your query.