When does SQL Server do an index seek vs index scan? - sql-server

What are the criteria that determine if SQL Server chooses to perform an index seek instead of an index scan?
I have a large table with a datetime2 column (and a non clustered index on that column).
My query contains this where condition
WHERE TIALETTURETAG_Data >= '2021-01-01 00:00:00'
AND TIALETTURETAG_Data <= '2021-12-31 23:59:59'`
Looking at the execution plan, SQL Server performs an index scan, is there a way to change its behaviour to make it execute an index seek that is much faster?
And why did it decide to perform an index scan?
NB: selecting only this fields (the primary key and the field where the condition is applied
SELECT
[TIALETTURETAG_Id], [TIALETTURETAG_Data]
FROM
TIALETTURETAG
WHERE
TIALETTURETAG_Data >= '2021-01-01 00:00:00'
AND TIALETTURETAG_Data <= '2021-12-31 23:59:59'
SQL Server performs an index seek.
This is the table structure:
CREATE TABLE [dbo].[TIALETTURETAG]
(
[TIALETTURETAG_Id] [int] IDENTITY(1,1) NOT NULL,
[TIALETTURETAG_IdLettura] [varchar](80) NOT NULL,
[TIALETTURETAG_IdSessione] [uniqueidentifier] NULL,
[TIALETTURETAG_Tag] [varchar](100) NOT NULL,
[TIALETTURETAG_TagOld] [varchar](100) NOT NULL,
[TIALETTURETAG_CodiceUtenza] [varchar](40) NOT NULL,
[TIALETTURETAG_Data] [datetime2](0) NOT NULL,
[TIALETTURETAG_Posizione] [geography] NULL,
[TIALETTURETAG_Cap] [varchar](5) NOT NULL,
[TIALETTURETAG_CodiceOds] [varchar](7) NOT NULL,
[TIALETTURETAG_Targa] [varchar](10) NOT NULL,
[TIALETTURETAG_Tipo] [char](1) NOT NULL,
[TIALETTURETAG_TipoTag] [char](1) NULL,
[TIALETTURETAG_TipoSegnalazione] [smallint] NULL,
[TIALETTURETAG_TipoEvento] [char](1) NOT NULL,
[TIALETTURETAG_SegnalazioneNote] [varchar](100) NOT NULL,
[TIALETTURETAG_Extra] [varchar](40) NOT NULL,
[TIALETTURETAG_IdOds] [int] NULL,
[TIALETTURETAG_IdDettOds] [int] NULL,
[TIALETTURETAG_IdAuto] [int] NULL,
[TIALETTURETAG_Stato] [tinyint] NOT NULL,
[TIALETTURETAG_Rifiuto] [varchar](12) NULL,
[TIALETTURETAG_Peso] [numeric](18, 6) NOT NULL,
[TIALETTURETAG_Volume] [numeric](18, 6) NOT NULL,
[TIALETTURETAG_Matricola] [varchar](50) NOT NULL,
[TIALETTURETAG_Nota] [varchar](2000) NOT NULL,
[TIALETTURETAG_Ranking] [tinyint] NULL,
[TIALETTURETAG_IdFile] [int] NULL,
[TIALETTURETAG_MacAddress] [varchar](17) NOT NULL,
[TIALETTURETAG_IMEI] [varchar](50) NOT NULL,
[TIALETTURETAG_UsrAPI] [int] NULL,
[TIALETTURETAG_SNBlackBox] [varchar](100) NOT NULL,
[TIALETTURETAG_Insert_Login] [varchar](50) NOT NULL,
[TIALETTURETAG_Insert_Data] [datetime2](0) NOT NULL,
[TIALETTURETAG_Update_Login] [varchar](50) NOT NULL,
[TIALETTURETAG_Update_Data] [datetime2](0) NOT NULL,
[TIALETTURETAG_Versione] [timestamp] NOT NULL,
[TIALETTURETAG_GisUtenza] [int] NULL,
[TIALETTURETAG_Indirizzo] [int] NULL,
[TIALETTURETAG_Sessione] [varchar](80) NOT NULL,
[TIALETTURETAG_CodiceAccesso] [varchar](100) NOT NULL,
CONSTRAINT [PK_TIALETTURETAG]
PRIMARY KEY CLUSTERED ([TIALETTURETAG_Id] ASC)
WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF,
IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON,
ALLOW_PAGE_LOCKS = ON, FILLFACTOR = 90) ON [PRIMARY]
) ON [PRIMARY] TEXTIMAGE_ON [PRIMARY]
GO
ALTER TABLE [dbo].[TIALETTURETAG]
ADD CONSTRAINT [DF_TIALETTURETAG_TIALETTURETAG_IdLettura]
DEFAULT ('') FOR [TIALETTURETAG_IdLettura]
GO
ALTER TABLE [dbo].[TIALETTURETAG]
ADD CONSTRAINT [DF_TIALETTURETAG_TIALETTURETAG_Tag]
DEFAULT ('') FOR [TIALETTURETAG_Tag]
GO
ALTER TABLE [dbo].[TIALETTURETAG]
ADD CONSTRAINT [DF_TIALETTURETAG_TIALETTURETAG_TagOld]
DEFAULT ('') FOR [TIALETTURETAG_TagOld]
GO
ALTER TABLE [dbo].[TIALETTURETAG]
ADD CONSTRAINT [DF_TIALETTURETAG_TIALETTURETAG_CodiceUtenza]
DEFAULT ('') FOR [TIALETTURETAG_CodiceUtenza]
GO
ALTER TABLE [dbo].[TIALETTURETAG]
ADD CONSTRAINT [DF_TIALETTURETAG_TIALETTURETAG_Data]
DEFAULT ('1900-01-01') FOR [TIALETTURETAG_Data]
GO
ALTER TABLE [dbo].[TIALETTURETAG]
ADD CONSTRAINT [DF_TIALETTURETAG_TIALETTURETAG_Cap]
DEFAULT ('') FOR [TIALETTURETAG_Cap]
GO
ALTER TABLE [dbo].[TIALETTURETAG]
ADD CONSTRAINT [DF_TIALETTURETAG_TIALETTURETAG_CodiceOds]
DEFAULT ('') FOR [TIALETTURETAG_CodiceOds]
GO
ALTER TABLE [dbo].[TIALETTURETAG]
ADD CONSTRAINT [DF_TIALETTURETAG_TIALETTURETAG_Targa]
DEFAULT ('') FOR [TIALETTURETAG_Targa]
GO
ALTER TABLE [dbo].[TIALETTURETAG]
ADD CONSTRAINT [DF_TIALETTURETAG_TIALETTURETAG_Tipo]
DEFAULT ('') FOR [TIALETTURETAG_Tipo]
GO
ALTER TABLE [dbo].[TIALETTURETAG]
ADD CONSTRAINT [DF_TIALETTURETAG_TIALETTURETAG_TipoEvento]
DEFAULT ('L') FOR [TIALETTURETAG_TipoEvento]
GO
ALTER TABLE [dbo].[TIALETTURETAG]
ADD CONSTRAINT [DF_TIALETTURETAG_TIALETTURETAG_SegnalazioneNote]
DEFAULT ('') FOR [TIALETTURETAG_SegnalazioneNote]
GO
ALTER TABLE [dbo].[TIALETTURETAG]
ADD CONSTRAINT [DF_TIALETTURETAG_TIALETTURETAG_Extra]
DEFAULT ('') FOR [TIALETTURETAG_Extra]
GO
ALTER TABLE [dbo].[TIALETTURETAG]
ADD CONSTRAINT [DF_TIALETTURETAG_TIALETTURETAG_Stato]
DEFAULT ((0)) FOR [TIALETTURETAG_Stato]
GO
ALTER TABLE [dbo].[TIALETTURETAG]
ADD CONSTRAINT [DF_TIALETTURETAG_TIALETTURETAG_Peso]
DEFAULT ((0)) FOR [TIALETTURETAG_Peso]
GO
ALTER TABLE [dbo].[TIALETTURETAG]
ADD CONSTRAINT [DF_TIALETTURETAG_TIALETTURETAG_Volume]
DEFAULT ((0)) FOR [TIALETTURETAG_Volume]
GO
ALTER TABLE [dbo].[TIALETTURETAG]
ADD CONSTRAINT [DF_TIALETTURETAG_TIALETTURETAG_Matricola]
DEFAULT ('') FOR [TIALETTURETAG_Matricola]
GO
ALTER TABLE [dbo].[TIALETTURETAG]
ADD CONSTRAINT [DF_TIALETTURETAG_TIALETTURETAG_Nota]
DEFAULT ('') FOR [TIALETTURETAG_Nota]
GO
ALTER TABLE [dbo].[TIALETTURETAG]
ADD CONSTRAINT [DF_TIALETTURETAG_TIALETTURETAG_MacAddress]
DEFAULT ('') FOR [TIALETTURETAG_MacAddress]
GO
ALTER TABLE [dbo].[TIALETTURETAG]
ADD CONSTRAINT [DF_TIALETTURETAG_TIALETTURETAG_IMEI]
DEFAULT ('') FOR [TIALETTURETAG_IMEI]
GO
ALTER TABLE [dbo].[TIALETTURETAG]
ADD CONSTRAINT [DF_TIALETTURETAG_TIALETTURETAG_SNBlackBox]
DEFAULT ('') FOR [TIALETTURETAG_SNBlackBox]
GO
ALTER TABLE [dbo].[TIALETTURETAG]
ADD CONSTRAINT [DF_TIALETTURETAG_TIALETTURETAG_Insert_Login]
DEFAULT (CASE WHEN LEFT(app_name(), (7)) <> 'ANTHEA_' THEN RIGHT(suser_sname(), (20)) ELSE RTRIM(REPLACE(app_name(), 'ANTHEA_', '')) END) FOR [TIALETTURETAG_Insert_Login]
GO
ALTER TABLE [dbo].[TIALETTURETAG]
ADD CONSTRAINT [DF_TIALETTURETAG_RISODS_Insert_Data]
DEFAULT (getdate()) FOR [TIALETTURETAG_Insert_Data]
GO
ALTER TABLE [dbo].[TIALETTURETAG]
ADD CONSTRAINT [DF_TIALETTURETAG_RISODS_Update_Login]
DEFAULT ('') FOR [TIALETTURETAG_Update_Login]
GO
ALTER TABLE [dbo].[TIALETTURETAG]
ADD CONSTRAINT [DF_TIALETTURETAG_RISODS_Update_Data]
DEFAULT ('1900-01-01') FOR [TIALETTURETAG_Update_Data]
GO
ALTER TABLE [dbo].[TIALETTURETAG]
ADD CONSTRAINT [DF_TIALETTURETAG_TIALETTURETAG_Sessione] DEFAULT ('') FOR [TIALETTURETAG_Sessione]
GO
ALTER TABLE [dbo].[TIALETTURETAG] ADD CONSTRAINT [DF_TIALETTURETAG_TIALETTURETAG_CodiceAccesso] DEFAULT ('') FOR [TIALETTURETAG_CodiceAccesso]
GO
ALTER TABLE [dbo].[TIALETTURETAG] WITH CHECK ADD CONSTRAINT [FK_TIALETTURETAG_AUTOMEZZI] FOREIGN KEY([TIALETTURETAG_IdAuto])
REFERENCES [dbo].[AUTOMEZZI] ([AUTOMEZZI_Identificatore])
GO
ALTER TABLE [dbo].[TIALETTURETAG] CHECK CONSTRAINT [FK_TIALETTURETAG_AUTOMEZZI]
GO
ALTER TABLE [dbo].[TIALETTURETAG] WITH CHECK ADD CONSTRAINT [FK_TIALETTURETAG_COMFILES] FOREIGN KEY([TIALETTURETAG_IdFile])
REFERENCES [dbo].[COMFILES] ([COMFILES_Id])
GO
ALTER TABLE [dbo].[TIALETTURETAG] CHECK CONSTRAINT [FK_TIALETTURETAG_COMFILES]
GO
ALTER TABLE [dbo].[TIALETTURETAG] WITH CHECK ADD CONSTRAINT [FK_TIALETTURETAG_COMTIPOSEGNALAZIONE] FOREIGN KEY([TIALETTURETAG_TipoSegnalazione])
REFERENCES [dbo].[COMTIPOSEGNALAZIONE] ([COMTIPOSEGNALAZIONE_id])
GO
ALTER TABLE [dbo].[TIALETTURETAG] CHECK CONSTRAINT [FK_TIALETTURETAG_COMTIPOSEGNALAZIONE]
GO
ALTER TABLE [dbo].[TIALETTURETAG] WITH CHECK ADD CONSTRAINT [FK_TIALETTURETAG_RISODS] FOREIGN KEY([TIALETTURETAG_IdOds])
REFERENCES [dbo].[RISODS] ([RISODS_Id])
GO
ALTER TABLE [dbo].[TIALETTURETAG] CHECK CONSTRAINT [FK_TIALETTURETAG_RISODS]
GO
ALTER TABLE [dbo].[TIALETTURETAG] WITH CHECK ADD CONSTRAINT [FK_TIALETTURETAG_RISRIFCONTRC] FOREIGN KEY([TIALETTURETAG_IdDettOds])
REFERENCES [dbo].[RISRIFCONTRC] ([RISRIFCONTRC_Id])
GO
ALTER TABLE [dbo].[TIALETTURETAG] CHECK CONSTRAINT [FK_TIALETTURETAG_RISRIFCONTRC]
GO
ALTER TABLE [dbo].[TIALETTURETAG] WITH CHECK ADD CONSTRAINT [FK_TIALETTURETAG_TIALETTURETAGINDIRIZZI] FOREIGN KEY([TIALETTURETAG_Indirizzo])
REFERENCES [dbo].[TIALETTURETAGINDIRIZZI] ([TIALETTURETAGINDIRIZZI_Id])
GO
ALTER TABLE [dbo].[TIALETTURETAG] CHECK CONSTRAINT [FK_TIALETTURETAG_TIALETTURETAGINDIRIZZI]
GO
ALTER TABLE [dbo].[TIALETTURETAG] WITH CHECK ADD CONSTRAINT [FK_TIALETTURETAG_TIALETTURETAGUTENZE] FOREIGN KEY([TIALETTURETAG_GisUtenza])
REFERENCES [dbo].[TIALETTURETAGUTENZE] ([TIALETTURETAGUTENZE_Id])
GO
ALTER TABLE [dbo].[TIALETTURETAG] CHECK CONSTRAINT [FK_TIALETTURETAG_TIALETTURETAGUTENZE]
GO
ALTER TABLE [dbo].[TIALETTURETAG] WITH CHECK ADD CONSTRAINT [FK_TIALETTURETAG_TIATIPOTAG] FOREIGN KEY([TIALETTURETAG_TipoTag])
REFERENCES [dbo].[TIATIPOTAG] ([TIATIPOTAG_Codice])
GO
ALTER TABLE [dbo].[TIALETTURETAG] CHECK CONSTRAINT [FK_TIALETTURETAG_TIATIPOTAG]
GO
ALTER TABLE [dbo].[TIALETTURETAG] WITH CHECK ADD CONSTRAINT [CK_TIALETTURETAG_Tag] CHECK ((case when [TIALETTURETAG_TipoEvento]='L' AND len([TIALETTURETAG_Tag])>(0) OR [TIALETTURETAG_TipoEvento]<>'L' then (1) else (0) end=(1)))
GO
ALTER TABLE [dbo].[TIALETTURETAG] CHECK CONSTRAINT [CK_TIALETTURETAG_Tag]
GO
ALTER TABLE [dbo].[TIALETTURETAG] WITH CHECK ADD CONSTRAINT [CK_TIALETTURETAG_Tipo] CHECK (([TIALETTURETAG_Tipo]='B' OR [TIALETTURETAG_Tipo]='C'))
GO
ALTER TABLE [dbo].[TIALETTURETAG] CHECK CONSTRAINT [CK_TIALETTURETAG_Tipo]
GO

Related

I do not know what's wrong with my database. Displays errors

I created two tables. And I need to have two Ids in the second table of Friends. UserId is Id from the UserInformation table. FriendId is Id already in this table. I need to make a relationship between these two tables and correctly make FK and PK. I tried to do it myself but it screams what I did not do right here - REFERENCES [UserInformation] (UserId)
I need your help to do the job correctly
CREATE TABLE [dbo].[UserInformation]
(
[Id] [INT] IDENTITY(1,1) NOT NULL,
[Login] [VARCHAR](50) NOT NULL,
[Password] [VARCHAR](50) NOT NULL,
[FirstName] [NCHAR](10) NOT NULL,
[LastName] [NCHAR](10) NOT NULL,
[Email] [VARCHAR](50) NOT NULL,
[RegistrationDate] [DATETIME] NOT NULL,
[Groups] [VARCHAR](50) NOT NULL
)
GO
CREATE TABLE [dbo].[Friends]
(
[UserId] [INT] NOT NULL,
[FriendId] [INT] NOT NULL,
PRIMARY KEY (FriendId),
CONSTRAINT FK_UserInformationFriend
FOREIGN KEY (UserId) REFERENCES [UserInformation](UserId)
)
GO
ALTER TABLE [dbo].[UserInformation]
ADD CONSTRAINT [DF_UserInformation_RegistrationDate]
DEFAULT (GETDATE()) FOR [RegistrationDate]
GO
ALTER TABLE UserInformation
ADD CONSTRAINT DF_UserInformation_Login_Unique UNIQUE(Login)
GO
ALTER TABLE UserInformation
ADD CONSTRAINT DF_UserInformation_Email_Unique UNIQUE(Email)
GO
ALTER TABLE UserInformation
ADD CONSTRAINT [PK_UserInformation] PRIMARY KEY ([Id])
GO
ALTER TABLE Friends
ADD CONSTRAINT [PK_Friends] PRIMARY KEY ([UserId])
GO
First Change it as:
CREATE TABLE [dbo].[UserInformation](
[Id] [int] IDENTITY(1,1) PRIMARY KEY NOT NULL,
[Login] [varchar](50) NOT NULL,
[Password] [varchar](50) NOT NULL,
[FirstName] [nchar](10) NOT NULL,
[LastName] [nchar](10) NOT NULL,
[Email] [varchar](50) NOT NULL,
[RegistrationDate] [datetime] NOT NULL,
[Groups] [varchar](50) NOT NULL
)
then:
CREATE TABLE [dbo].[Friends](
[UserId] [int] NOT NULL,
[FriendId] [int] NOT NULL,
PRIMARY KEY (FriendId),
CONSTRAINT FK_UserInformationFriend FOREIGN KEY (UserId)
REFERENCES [UserInformation](Id)
)
and Last:
ALTER TABLE [dbo].[UserInformation]
ADD CONSTRAINT [DF_UserInformation_RegistrationDate] DEFAULT
(getdate()) FOR [RegistrationDate]
GO
ALTER TABLE UserInformation
ADD CONSTRAINT DF_UserInformation_Login_Unique UNIQUE (Login)
GO
ALTER TABLE UserInformation
ADD CONSTRAINT DF_UserInformation_Email_Unique UNIQUE (Email)
No need these as primary is already set for both tables:
ALTER TABLE UserInformation
ADD CONSTRAINT [PK_UserInformation] PRIMARY KEY ([Id])
GO
ALTER TABLE Friends
ADD CONSTRAINT [PK_Friends] PRIMARY KEY ([UserId])
GO
Note: if you need multiple primary keys then go for composite primarys:
primary key (FriendId, UserId)

Foreign Key Relationship possible performance issues

We have a User table with a GUID aka uniqueidentifier as the PK. Nearly every other table in the database ties back to this table with 4 FK references. When I look at the DB diagram it looks like a 100 lane highway coming out of the User table because of the CreatedBy, CreatedByProxy, UpdatedBy, UpdatedByProxy foreign keys.
I was brought onto this project after it was already past inception and in production already, and with performance issues.
I was wondering if this DB pattern will cause major growing pains when the user list starts to grow. Are we going to run into more performance issues in the future because of this, or if we create an index will keeping the foreign keys cause the indexes to be huge. I just don't remember a website that I've worked on before that had the foreign keys to this extent before, and I'm worried about future proofing/fixing it. I'm really just trying to justify whether or not to keep or remove the foreign keys or modify the structure so that
User Table:
CREATE TABLE [dbo].[aspnet_Users](
[ApplicationId] [uniqueidentifier] NOT NULL,
[UserId] [uniqueidentifier] NOT NULL, -- ***** Here is the PK
[UserName] [nvarchar](256) NOT NULL,
[LoweredUserName] [nvarchar](256) NOT NULL,
[MobileAlias] [nvarchar](16) NULL,
[IsAnonymous] [bit] NOT NULL,
[LastActivityDate] [datetime] NOT NULL,
PRIMARY KEY NONCLUSTERED
(
[UserId] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]
One other Table that references User:
CREATE TABLE [dbo].[Email](
[EmailId] [int] IDENTITY(1,1) NOT NULL,
[PersonId] [int] NULL,
[InstitutionId] [int] NULL,
[EmailTypeId] [int] NOT NULL,
[EmailAddress] [varchar](254) NOT NULL,
[IsFlaggedImportant] [bit] NOT NULL,
[IsDistrictRecord] [bit] NOT NULL,
[IsActive] [bit] NOT NULL,
[Created] [datetime] NOT NULL,
[CreatedBy] [uniqueidentifier] NOT NULL, -- ***** FK 1
[Proxy] [uniqueidentifier] NULL, -- ***** FK 2
[Updated] [datetime] NULL,
[UpdatedBy] [uniqueidentifier] NULL, -- ***** FK 3
[UpdateProxy] [uniqueidentifier] NULL, -- ***** FK 4
CONSTRAINT [PK_Email] PRIMARY KEY CLUSTERED
(
[EmailId] 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
SET ANSI_PADDING OFF
GO
ALTER TABLE [dbo].[Email] ADD CONSTRAINT [DF_Email_IsPrimary] DEFAULT ((0)) FOR [IsFlaggedImportant]
GO
ALTER TABLE [dbo].[Email] ADD CONSTRAINT [DF_Email_IsDistrictRecord] DEFAULT ((0)) FOR [IsDistrictRecord]
GO
ALTER TABLE [dbo].[Email] ADD CONSTRAINT [DF_Email_IsActive] DEFAULT ((0)) FOR [IsActive]
GO
ALTER TABLE [dbo].[Email] ADD CONSTRAINT [DF_Email_Created] DEFAULT (getdate()) FOR [Created]
GO
ALTER TABLE [dbo].[Email] WITH CHECK ADD CONSTRAINT [FK_Email_CreatedByUser] FOREIGN KEY([CreatedBy])
REFERENCES [dbo].[aspnet_Users] ([UserId])
GO
ALTER TABLE [dbo].[Email] CHECK CONSTRAINT [FK_Email_CreatedByUser]
GO
ALTER TABLE [dbo].[Email] WITH CHECK ADD CONSTRAINT [FK_Email_EmailType] FOREIGN KEY([EmailTypeId])
REFERENCES [dbo].[EmailType] ([EmailTypeId])
GO
ALTER TABLE [dbo].[Email] CHECK CONSTRAINT [FK_Email_EmailType]
GO
ALTER TABLE [dbo].[Email] WITH CHECK ADD CONSTRAINT [FK_Email_Institution] FOREIGN KEY([InstitutionId])
REFERENCES [dbo].[Institution] ([InstitutionId])
GO
ALTER TABLE [dbo].[Email] CHECK CONSTRAINT [FK_Email_Institution]
GO
ALTER TABLE [dbo].[Email] WITH CHECK ADD CONSTRAINT [FK_Email_Person] FOREIGN KEY([PersonId])
REFERENCES [dbo].[Person] ([PersonId])
GO
ALTER TABLE [dbo].[Email] CHECK CONSTRAINT [FK_Email_Person]
GO
ALTER TABLE [dbo].[Email] WITH CHECK ADD CONSTRAINT [FK_Email_ProxyByUser] FOREIGN KEY([Proxy])
REFERENCES [dbo].[aspnet_Users] ([UserId])
GO
ALTER TABLE [dbo].[Email] CHECK CONSTRAINT [FK_Email_ProxyByUser]
GO
ALTER TABLE [dbo].[Email] WITH CHECK ADD CONSTRAINT [FK_Email_ProxyUpdateByUser] FOREIGN KEY([UpdateProxy])
REFERENCES [dbo].[aspnet_Users] ([UserId])
GO
ALTER TABLE [dbo].[Email] CHECK CONSTRAINT [FK_Email_ProxyUpdateByUser]
GO
ALTER TABLE [dbo].[Email] WITH CHECK ADD CONSTRAINT [FK_Email_UpdatedByUser] FOREIGN KEY([UpdatedBy])
REFERENCES [dbo].[aspnet_Users] ([UserId])
GO
ALTER TABLE [dbo].[Email] CHECK CONSTRAINT [FK_Email_UpdatedByUser]
GO
ALTER TABLE [dbo].[Email] WITH CHECK ADD CONSTRAINT [CK_Email_Person_Or_Institution] CHECK (([PersonId] IS NOT NULL AND [InstitutionId] IS NULL OR [PersonId] IS NULL AND [InstitutionId] IS NOT NULL))
GO
ALTER TABLE [dbo].[Email] CHECK CONSTRAINT [CK_Email_Person_Or_Institution]
GO
I was brought onto this project after it was already past inception
and in production already, and with performance issues.
You don't say what those performance issues are, so I'll confine my remarks to the foreign keys.
When I look at the DB diagram it looks like a 100 lane highway coming
out of the User table because of the CreatedBy, CreatedByProxy,
UpdatedBy, UpdatedByProxy foreign keys.
When I see columns like that, I have to ask whether they contain information about the business entity--a person's email address in this case--or information about the row that entity happens to inhabit.
It looks like they contain information about the row. (But I could be wrong.)
If they do contain information about the row, and they're not needed in most queries, you can move them to another table. If you move them, you have to be more careful about inserting rows into dbo.Email.
CREATE TABLE [dbo].[Email](
[EmailId] [int] IDENTITY(1,1) NOT NULL,
[PersonId] [int] NULL,
[InstitutionId] [int] NULL,
[EmailTypeId] [int] NOT NULL,
[EmailAddress] [varchar](254) NOT NULL,
[IsFlaggedImportant] [bit] NOT NULL,
[IsDistrictRecord] [bit] NOT NULL,
[IsActive] [bit] NOT NULL,
CONSTRAINT [PK_Email] PRIMARY KEY CLUSTERED ([EmailID])
);
CREATE TABLE [dbo].[Email_audit](
[EmailID] [int] PRIMARY KEY REFERENCES [Email] ([EmailID]),
[Created] [datetime] NOT NULL,
[CreatedBy] [uniqueidentifier] NOT NULL, -- ***** FK 1
[Proxy] [uniqueidentifier] NULL, -- ***** FK 2
[Updated] [datetime] NULL,
[UpdatedBy] [uniqueidentifier] NULL, -- ***** FK 3
[UpdateProxy] [uniqueidentifier] NULL -- ***** FK 4
);
These kinds of tables are commonly used to provide some kind of audit trail. Whether you can cascade deletes is application-dependent. In some apps, you need to store the email address here instead of the email id number, and use no foreign key references. (This allows deleting rows from dbo.Email while retaining some information about what's happened to the row.)
Moving these columns reduces the width of a row in dbo.Email by about 80 bytes, not counting overhead. That usually improves performance of SELECT statements in the tables they're moved from. (Narrower rows; more rows per page.)
Moving these columns complicates inserting and updating rows, though. All inserts and updates have to hit two tables.

How can I force one to one relationship on SQL Server 2008 or 2008 R2

Here is my scenario on SQL Server 2008 R2:
This is my first table:
CREATE TABLE [dbo].[Foos](
[FooId] [int] IDENTITY(1,1) NOT NULL,
[Name] [nvarchar](50) NULL,
CONSTRAINT [PK_Foos] PRIMARY KEY CLUSTERED
(
[FooId] ASC
)
) ON [PRIMARY]
This is the second table which has a relationship to Foos table:
CREATE TABLE [dbo].[Bars](
[BarId] [int] IDENTITY(1,1) NOT NULL,
[FooId] [int] NOT NULL,
[Name] [nvarchar](50) NULL,
CONSTRAINT [PK_Bars] PRIMARY KEY CLUSTERED
(
[BarId] ASC
)
) ON [PRIMARY]
Go
ALTER TABLE [dbo].[Bars] WITH CHECK ADD CONSTRAINT [FK_Bars_Foos] FOREIGN KEY([FooId])
REFERENCES [dbo].[Foos] ([FooId])
ON DELETE CASCADE
GO
But it is not one to one. What should I do to force this to be one to one relationship? Should I use check constraints?
Add a unique constraint to FooId in Bars.
However, you don't need BarID then because they have the same key. So it looks like this
CREATE TABLE [dbo].[Bars] (
[FooId] [int] NOT NULL,
[Name] [nvarchar](50) NULL,
CONSTRAINT [PK_Bars] PRIMARY KEY CLUSTERED (FooId),
CONSTRAINT [FK_Bars_Foos] FOREIGN KEY([FooId])
REFERENCES [dbo].[Foos] ([FooId])
ON DELETE CASCADE
)
GO
However again, you don't need Bars at all: it is one table...
You can keep Identity column(BarID) also. Then Unique key will help you out from this problem.
IF NOT EXISTS(SELECT OBJECT_ID from sys.objects WHERE name ='foo_bars')
alter table bars add constraint foo_bars unique(fooid)

how to alter table Composite primary key

CREATE TABLE [dbo].[INVS_ITEM_LOCATIONS]
([DEPARTMENT_CODE] [varchar](3) COLLATE SQL_Latin1_General_CP1_CI_AS NOT NULL,
[IM_INV_NO] [numeric](10, 0) NOT NULL,
[LOCATION_CODE] [varchar](2) COLLATE SQL_Latin1_General_CP1_CI_AS NOT NULL,
[CURR_QTY] [numeric](10, 0) NOT NULL CONSTRAINT [DF__INVS_ITEM__CURR___1352D76D] DEFAULT ((0)),
[DO_QTY] [numeric](10, 0) NOT NULL CONSTRAINT [DF__INVS_ITEM__DO_QT__1446FBA6] DEFAULT ((0)),
[ALLOC_QTY] [numeric](10, 0) NOT NULL CONSTRAINT [DF__INVS_ITEM__ALLOC__153B1FDF] DEFAULT ((0)),
[YOB_QTY] [numeric](10, 0) NOT NULL CONSTRAINT [DF__INVS_ITEM__YOB_Q__162F4418] DEFAULT ((0)),
[FOC_QTY] [numeric](10, 0) NULL CONSTRAINT [DF__INVS_ITEM__FOC_Q__17236851] DEFAULT ((0)),
[USER_CREATED] [varchar](25) COLLATE SQL_Latin1_General_CP1_CI_AS NOT NULL,
[DATE_CREATED] [datetime] NOT NULL,
[USER_MODIFIED] [varchar](25) COLLATE SQL_Latin1_General_CP1_CI_AS NULL,
[DATE_MODIFIED] [datetime] NULL,
CONSTRAINT [INVS_ITEM_LOCATIONS_PK]
PRIMARY KEY CLUSTERED ([DEPARTMENT_CODE] ASC,
[IM_INV_NO] ASC, [LOCATION_CODE] ASC)
WITH (IGNORE_DUP_KEY = OFF) ON [PRIMARY]
) ON [PRIMARY]
This is my table structure ......how can I remove the composite primary key in table and also I should add foreign key to im_inv_no reference table is invs_location which contain im_inv_no and the department_code should be same primary key .pls help
To remove your composite primary key, use:
ALTER TABLE dbo.INVS_ITEM_LOCATIONS
DROP CONSTRAINT INVS_ITEM_LOCATIONS_PK
To add a foreign key, use this:
ALTER TABLE dbo.INVS_ITEM_LOCATIONS
ADD CONSTRAINT FK_INV_NO_REFERENCE
FOREIGN KEY(IM_INV_NO, DEPARTMENT_CODE)
REFERENCES dbo.invs_location(IM_INV_NO, DEPARTMENT_CODE)
These are all really basic beginner SQL questions - I would strongly recommend you read one of the various good SQL tutorials out there to get used to SQL first, before posting each and every single little question here....
W3Schools SQL Tutorial
Marc
You can create new tables with modifications you need, copy your data then renaming new talbes to the same names as old tables and deleting old ones. It is probably the most efficient way as well.

Deletes in one-to-one relationships? Normal behavior?

When working in Access, whenever I delete a record from one table - it's corresponding record in another table is also deleted when defined as a one-to-one relationship. This would be normal behavior when I tell it to enforce referential integrity with concerns to deletes and updates (how I understand it). However, it seems to also do it when I leave the enforce referential integrity option for deletes cleared, or when I leave the entire section on referential integrity cleared as well.
Basically, I have one table which is a list of suppliers that is a source for another database application that wasn't written by myself. I am using this supplier table in my application, augmenting the information stored in the first program with information entered by the user in the second program in a separate table - but linked using a one-to-one relationship (relationship using primary keys in both tables).
I don't want a delete of the secondary information record to result in the deletion of the data in the primary table - which would cause major issues (to put it mildly) in the first program. Is there a way to do this?
--Edited to add on 5/27/2009 # 1600--
Here is the SQL script to create the Supplier_Master table from the first application:
USE [gtdata_test]
GO
/****** Object: Table [dbo].[Supplier_Master] Script Date: 05/27/2009 15:58:17 ******/
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
CREATE TABLE [dbo].[Supplier_Master](
[Supplier_Code] [nvarchar](50) NOT NULL,
[Supplier_Master_Name] [nvarchar](50) NULL,
[Salutation] [nvarchar](50) NULL,
[Contact] [nvarchar](50) NULL,
[Phone] [nvarchar](50) NULL,
[Fax] [nvarchar](50) NULL,
[EMail] [nvarchar](50) NULL,
[Address] [nvarchar](50) NULL,
[City] [nvarchar](50) NULL,
[State] [nvarchar](50) NULL,
[Zip] [nvarchar](50) NULL,
[Country] [nvarchar](50) NULL,
[Last_Review] [datetime] NULL,
[Last_Rating] [datetime] NULL,
[Last_Received] [datetime] NULL,
[Last_Reject] [datetime] NULL,
[Enabled] [int] NULL,
[User1] [nvarchar](50) NULL,
[User2] [nvarchar](50) NULL,
[SupType] [nvarchar](50) NULL,
CONSTRAINT [Supplier_Master$PrimaryKey] PRIMARY KEY CLUSTERED
(
[Supplier_Code] 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].[Supplier_Master] WITH NOCHECK ADD CONSTRAINT [SSMA_CC$Supplier_Master$Address$disallow_zero_length] CHECK ((len([Address])>(0)))
GO
ALTER TABLE [dbo].[Supplier_Master] CHECK CONSTRAINT [SSMA_CC$Supplier_Master$Address$disallow_zero_length]
GO
ALTER TABLE [dbo].[Supplier_Master] WITH NOCHECK ADD CONSTRAINT [SSMA_CC$Supplier_Master$City$disallow_zero_length] CHECK ((len([City])>(0)))
GO
ALTER TABLE [dbo].[Supplier_Master] CHECK CONSTRAINT [SSMA_CC$Supplier_Master$City$disallow_zero_length]
GO
ALTER TABLE [dbo].[Supplier_Master] WITH NOCHECK ADD CONSTRAINT [SSMA_CC$Supplier_Master$Contact$disallow_zero_length] CHECK ((len([Contact])>(0)))
GO
ALTER TABLE [dbo].[Supplier_Master] CHECK CONSTRAINT [SSMA_CC$Supplier_Master$Contact$disallow_zero_length]
GO
ALTER TABLE [dbo].[Supplier_Master] WITH NOCHECK ADD CONSTRAINT [SSMA_CC$Supplier_Master$Country$disallow_zero_length] CHECK ((len([Country])>(0)))
GO
ALTER TABLE [dbo].[Supplier_Master] CHECK CONSTRAINT [SSMA_CC$Supplier_Master$Country$disallow_zero_length]
GO
ALTER TABLE [dbo].[Supplier_Master] WITH NOCHECK ADD CONSTRAINT [SSMA_CC$Supplier_Master$EMail$disallow_zero_length] CHECK ((len([EMail])>(0)))
GO
ALTER TABLE [dbo].[Supplier_Master] CHECK CONSTRAINT [SSMA_CC$Supplier_Master$EMail$disallow_zero_length]
GO
ALTER TABLE [dbo].[Supplier_Master] WITH NOCHECK ADD CONSTRAINT [SSMA_CC$Supplier_Master$Fax$disallow_zero_length] CHECK ((len([Fax])>(0)))
GO
ALTER TABLE [dbo].[Supplier_Master] CHECK CONSTRAINT [SSMA_CC$Supplier_Master$Fax$disallow_zero_length]
GO
ALTER TABLE [dbo].[Supplier_Master] WITH NOCHECK ADD CONSTRAINT [SSMA_CC$Supplier_Master$Phone$disallow_zero_length] CHECK ((len([Phone])>(0)))
GO
ALTER TABLE [dbo].[Supplier_Master] CHECK CONSTRAINT [SSMA_CC$Supplier_Master$Phone$disallow_zero_length]
GO
ALTER TABLE [dbo].[Supplier_Master] WITH NOCHECK ADD CONSTRAINT [SSMA_CC$Supplier_Master$Salutation$disallow_zero_length] CHECK ((len([Salutation])>(0)))
GO
ALTER TABLE [dbo].[Supplier_Master] CHECK CONSTRAINT [SSMA_CC$Supplier_Master$Salutation$disallow_zero_length]
GO
ALTER TABLE [dbo].[Supplier_Master] WITH NOCHECK ADD CONSTRAINT [SSMA_CC$Supplier_Master$State$disallow_zero_length] CHECK ((len([State])>(0)))
GO
ALTER TABLE [dbo].[Supplier_Master] CHECK CONSTRAINT [SSMA_CC$Supplier_Master$State$disallow_zero_length]
GO
ALTER TABLE [dbo].[Supplier_Master] WITH NOCHECK ADD CONSTRAINT [SSMA_CC$Supplier_Master$Supplier_Code$disallow_zero_length] CHECK ((len([Supplier_Code])>(0)))
GO
ALTER TABLE [dbo].[Supplier_Master] CHECK CONSTRAINT [SSMA_CC$Supplier_Master$Supplier_Code$disallow_zero_length]
GO
ALTER TABLE [dbo].[Supplier_Master] WITH NOCHECK ADD CONSTRAINT [SSMA_CC$Supplier_Master$Supplier_Master_Name$disallow_zero_length] CHECK ((len([Supplier_Master_Name])>(0)))
GO
ALTER TABLE [dbo].[Supplier_Master] CHECK CONSTRAINT [SSMA_CC$Supplier_Master$Supplier_Master_Name$disallow_zero_length]
GO
ALTER TABLE [dbo].[Supplier_Master] WITH NOCHECK ADD CONSTRAINT [SSMA_CC$Supplier_Master$SupType$disallow_zero_length] CHECK ((len([SupType])>(0)))
GO
ALTER TABLE [dbo].[Supplier_Master] CHECK CONSTRAINT [SSMA_CC$Supplier_Master$SupType$disallow_zero_length]
GO
ALTER TABLE [dbo].[Supplier_Master] WITH NOCHECK ADD CONSTRAINT [SSMA_CC$Supplier_Master$User1$disallow_zero_length] CHECK ((len([User1])>(0)))
GO
ALTER TABLE [dbo].[Supplier_Master] CHECK CONSTRAINT [SSMA_CC$Supplier_Master$User1$disallow_zero_length]
GO
ALTER TABLE [dbo].[Supplier_Master] WITH NOCHECK ADD CONSTRAINT [SSMA_CC$Supplier_Master$User2$disallow_zero_length] CHECK ((len([User2])>(0)))
GO
ALTER TABLE [dbo].[Supplier_Master] CHECK CONSTRAINT [SSMA_CC$Supplier_Master$User2$disallow_zero_length]
GO
ALTER TABLE [dbo].[Supplier_Master] WITH NOCHECK ADD CONSTRAINT [SSMA_CC$Supplier_Master$Zip$disallow_zero_length] CHECK ((len([Zip])>(0)))
GO
ALTER TABLE [dbo].[Supplier_Master] CHECK CONSTRAINT [SSMA_CC$Supplier_Master$Zip$disallow_zero_length]
GO
ALTER TABLE [dbo].[Supplier_Master] ADD DEFAULT ((0)) FOR [Enabled]
GO
Here is the SQL script to create the tblSupplierInfo table from the second application:
USE [instkeeper_test]
GO
/****** Object: Table [dbo].[tblSupplierInfo] Script Date: 05/27/2009 15:57:30 ******/
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
CREATE TABLE [dbo].[tblSupplierInfo](
[strSupplierID] [nvarchar](50) NOT NULL,
[bolSupAltShipAddyRep] [bit] NULL,
[bolSupAltShipAddyCal] [bit] NULL,
[bolSupInsistNet30] [bit] NULL,
[bolRMARequireRepair] [bit] NULL,
[bolRMARequireCalibration] [bit] NULL,
[bolSupShipOrCourier] [bit] NULL,
[bolSupRequireMSDS] [bit] NULL,
[bolSupBlanketPO] [bit] NULL,
[bolSupRequirePricing] [bit] NULL,
[bolSupBlankPricing] [bit] NULL,
[bolSupFaxPOSend] [bit] NULL,
[bolAdditionalPaperworkRepair] [bit] NULL,
[bolAdditionalPaperworkCalibration] [bit] NULL,
[strRMARepairWordage] [nvarchar](100) NULL,
[strRMACalibrationWordage] [nvarchar](100) NULL,
[intBlanketPO] [int] NULL,
[bolUseFedExNumber] [bit] NULL,
[strFedExNumber] [nvarchar](150) NULL,
[bolUseUPSNumber] [bit] NULL,
[strUPSNumber] [nvarchar](150) NULL,
[bolSupA2LAAccredited] [bit] NULL,
[bolSupFreightAllow] [bit] NULL,
[bolSupFreightOnly] [bit] NULL,
[bolSupUseMiscNum] [bit] NULL,
[strSupMiscFreightNum] [nvarchar](150) NULL,
CONSTRAINT [tblSupplierInfo$PrimaryKey] PRIMARY KEY CLUSTERED
(
[strSupplierID] 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
EXEC sys.sp_addextendedproperty #name=N'MS_Description', #value=N'Supplier Name' , #level0type=N'SCHEMA',#level0name=N'dbo', #level1type=N'TABLE',#level1name=N'tblSupplierInfo', #level2type=N'COLUMN',#level2name=N'strSupplierID'
GO
EXEC sys.sp_addextendedproperty #name=N'MS_Description', #value=N'Alternate Shipping Address - Repairs?' , #level0type=N'SCHEMA',#level0name=N'dbo', #level1type=N'TABLE',#level1name=N'tblSupplierInfo', #level2type=N'COLUMN',#level2name=N'bolSupAltShipAddyRep'
GO
EXEC sys.sp_addextendedproperty #name=N'MS_Description', #value=N'Alternate Shipping Address - Calibrations?' , #level0type=N'SCHEMA',#level0name=N'dbo', #level1type=N'TABLE',#level1name=N'tblSupplierInfo', #level2type=N'COLUMN',#level2name=N'bolSupAltShipAddyCal'
GO
EXEC sys.sp_addextendedproperty #name=N'MS_Description', #value=N'Force Net 30 Wordage?' , #level0type=N'SCHEMA',#level0name=N'dbo', #level1type=N'TABLE',#level1name=N'tblSupplierInfo', #level2type=N'COLUMN',#level2name=N'bolSupInsistNet30'
GO
EXEC sys.sp_addextendedproperty #name=N'MS_Description', #value=N'Do repairs require RMAs?' , #level0type=N'SCHEMA',#level0name=N'dbo', #level1type=N'TABLE',#level1name=N'tblSupplierInfo', #level2type=N'COLUMN',#level2name=N'bolRMARequireRepair'
GO
EXEC sys.sp_addextendedproperty #name=N'MS_Description', #value=N'Do calibrations require RMAs?' , #level0type=N'SCHEMA',#level0name=N'dbo', #level1type=N'TABLE',#level1name=N'tblSupplierInfo', #level2type=N'COLUMN',#level2name=N'bolRMARequireCalibration'
GO
EXEC sys.sp_addextendedproperty #name=N'MS_Description', #value=N'Use Courier?' , #level0type=N'SCHEMA',#level0name=N'dbo', #level1type=N'TABLE',#level1name=N'tblSupplierInfo', #level2type=N'COLUMN',#level2name=N'bolSupShipOrCourier'
GO
EXEC sys.sp_addextendedproperty #name=N'MS_Description', #value=N'Requires MSDS(s)?' , #level0type=N'SCHEMA',#level0name=N'dbo', #level1type=N'TABLE',#level1name=N'tblSupplierInfo', #level2type=N'COLUMN',#level2name=N'bolSupRequireMSDS'
GO
ALTER TABLE [dbo].[tblSupplierInfo] ADD DEFAULT ((0)) FOR [bolSupAltShipAddyRep]
GO
ALTER TABLE [dbo].[tblSupplierInfo] ADD DEFAULT ((0)) FOR [bolSupAltShipAddyCal]
GO
ALTER TABLE [dbo].[tblSupplierInfo] ADD DEFAULT ((0)) FOR [bolSupInsistNet30]
GO
ALTER TABLE [dbo].[tblSupplierInfo] ADD DEFAULT ((0)) FOR [bolRMARequireRepair]
GO
ALTER TABLE [dbo].[tblSupplierInfo] ADD DEFAULT ((0)) FOR [bolRMARequireCalibration]
GO
ALTER TABLE [dbo].[tblSupplierInfo] ADD DEFAULT ((0)) FOR [bolSupShipOrCourier]
GO
ALTER TABLE [dbo].[tblSupplierInfo] ADD DEFAULT ((0)) FOR [bolSupRequireMSDS]
GO
ALTER TABLE [dbo].[tblSupplierInfo] ADD DEFAULT ((0)) FOR [bolSupBlanketPO]
GO
ALTER TABLE [dbo].[tblSupplierInfo] ADD DEFAULT ((1)) FOR [bolSupRequirePricing]
GO
ALTER TABLE [dbo].[tblSupplierInfo] ADD DEFAULT ((0)) FOR [bolSupBlankPricing]
GO
ALTER TABLE [dbo].[tblSupplierInfo] ADD DEFAULT ((0)) FOR [bolSupFaxPOSend]
GO
ALTER TABLE [dbo].[tblSupplierInfo] ADD DEFAULT ((0)) FOR [bolAdditionalPaperworkRepair]
GO
ALTER TABLE [dbo].[tblSupplierInfo] ADD DEFAULT ((0)) FOR [bolAdditionalPaperworkCalibration]
GO
ALTER TABLE [dbo].[tblSupplierInfo] ADD DEFAULT ('RMA #') FOR [strRMARepairWordage]
GO
ALTER TABLE [dbo].[tblSupplierInfo] ADD DEFAULT ('RMA #') FOR [strRMACalibrationWordage]
GO
ALTER TABLE [dbo].[tblSupplierInfo] ADD DEFAULT ((0)) FOR [intBlanketPO]
GO
ALTER TABLE [dbo].[tblSupplierInfo] ADD DEFAULT ((0)) FOR [bolUseFedExNumber]
GO
ALTER TABLE [dbo].[tblSupplierInfo] ADD DEFAULT ((0)) FOR [bolUseUPSNumber]
GO
Yes it's normal behaviour. If your form is based on a query that contains a single one-to-one relationship and you delete a "record" it will delete records in both tables.
You need to suppress the normal delete process and run the delete manually via a custom button.
Private Sub Form_Delete(Cancel As Integer)
'this cancels all normal deletes'
Cancel = True
End Sub
Then create a Delete button
Private Sub cmdDelete_Click()
Dim oDB as DAO.Database
oDB.Execute "DELETE * FROM tblSupplierInfo WHERE strSupplierID = '" & Me.strSupplierID & "'", dbFailOnError
Me.Requery
End Sub
How is SQL Server involved? If you don't have cascading deletes on in either Access or SQL Server, perhaps there is a trigger?

Resources