add a constraint on a datetime column - sql-server

i want to to add a constraint onto a ID column and a date time column, so that an id can only be entered once in a day
alter table Table1
...
add constraint pk_id Primary Key (datetime,ID)
If an id has been inserted for the following datetime 2015-03-17 12:48:00, it would not get inserted again on the same datetime, but if the time changes to 2015-03-17 12:45:00 the id gets entered again.
Is there a way to add the constraint to just the date part of the datetime column?

I don't think you can but you have different alternatives:
Change your column to just have the date part populated
Create a computed column where you remove the time part and create the unique index used this column instead.
EDIT: as per #a-ツ comment there are other options:
Split the column in two, one to store the date and other to store the time part, so you can create de index over the date one

You have to give composite primary key or check constraint..
Check this example. For composite key, on design mode, just select both column and right click and select "primary-key".
CREATE TABLE [dbo].[Table_1](
[id] [int] NOT NULL,
[datecolumn] [datetime] NOT NULL,
[name] [varchar](50) NULL,
CONSTRAINT [PK_Table_1] PRIMARY KEY CLUSTERED
(
[id] ASC,
[datecolumn] ASC
)
) ON [PRIMARY]
GO
insert into Table_1 values (1, '2014-03-17 00:00:00.000', 'othercolumnvalue')
insert into Table_1 values (1, '2014-03-17 12:00:00.000', 'othercolumnvalue')
insert into Table_1 values (1, '2014-03-17 02:10:59.000', 'othercolumnvalue')
--this will give error as you already entered the same value.
insert into Table_1 values (1, '2014-03-17 00:00:00.000', 'othercolumnvalue')
how do I make a composite key with SQL Server Management Studio?

Related

Altering an existing column to 'Primary Key' and 'NOT NULL' without dropping the table

I have a table named dbo.ReferenceDetails which contains several millions of records. Here is the create and select script of my table :
CREATE TABLE [dbo].[RefDetails](
[REQ_XREF_TYPE] [varchar](12) NULL
, [REQUEST_ID] [varchar](24) NULL
, [CROSS_REFERENCE] [varchar](32) NULL
, [RUN_BY] [varchar](100) NULL
, [RUN_DATE] [datetime] NULL
, [ISCURRENTRECORD] [int] NULL
, [RECORDSTARTDATE] [datetime2](7) NULL
, [RECORDENDDATE] [datetime2](7) NULL
, [UPDATE_FLAG] [varchar](50) NULL
, [SECUREFLAG] [int] NULL
, [EVENT_TIMESTAMP] [datetime2](7) NULL
) ON [PRIMARY]
SELECT TOP (10)
[REQ_XREF_TYPE]
,[REQUEST_ID]
,[CROSS_REFERENCE]
,[RUN_BY]
,[RUN_DATE]
,[ISCURRENTRECORD]
,[RECORDSTARTDATE]
,[RECORDENDDATE]
,[UPDATE_FLAG]
,[SECUREFLAG]
,[EVENT_TIMESTAMP]
FROM [dbo].[ReferenceDetails]
Can I alter the table so that REQ_XREF_TYPE, ISCURRENTRECORD and EVENT_TIMESTAMP is Primary Key and NOT NULL without dropping the table?
Your response will be appreciated. :)
See below. You first need to convert the columns to NOT NULL then you create the Primary Key. If you already have data in the table then the creation of the primary key may take some time.
ALTER TABLE [dbo].[RefDetails] ALTER COLUMN [REQ_XREF_TYPE] VARCHAR(12) NOT NULL
ALTER TABLE [dbo].[RefDetails] ALTER COLUMN [ISCURRENTRECORD] INT NOT NULL
ALTER TABLE [dbo].[RefDetails] ALTER COLUMN [EVENT_TIMESTAMP] DATETIME2(7) NOT NULL
ALTER TABLE [dbo].[RefDetails] ADD CONSTRAINT PK_RefDetails PRIMARY KEY ([REQ_XREF_TYPE],[ISCURRENTRECORD],[EVENT_TIMESTAMP]);
Note: Your creation script says the table name is RefDetails but your OP says ReferenceDetails. I went with the creation script name.
Update:
The Primary Key requires that any column(s) selected contain a unique combination - duplicates are not allowed. If duplicates exist, the creation of the primary key will fail. To check for duplicates before creating a primary key, run the following:
SELECT [REQ_XREF_TYPE], [ISCURRENTRECORD], [EVENT_TIMESTAMP], CountDupes = COUNT(1)
FROM [dbo].[RefDetails]
GROUP BY [REQ_XREF_TYPE], [ISCURRENTRECORD], [EVENT_TIMESTAMP]
HAVING COUNT(1) > 1
ORDER BY [REQ_XREF_TYPE], [ISCURRENTRECORD], [EVENT_TIMESTAMP]
You are expecting 0 results, which means there are no duplicates. Any result will identify the unique set of duplicate records along with the number of times they are duplicates (see the CountDupes column result).
If you get 0 results, then you are clear to create the primary key.
If you get any results, then you will need to address this (i.e., remove the duplicates or include additional columns that create a unique combination).

How to automatically create rows and pass values to other tables

There are three tables in database:
"BusinessEntity " which has the identity column "BusinessEntityID" as Primary Key (as well as rowguid and ModifiedDate columns).
"Firm" which has similarly the identity column "BusinessEntityID" as Primary Key, which is also a Foreign Key to BusinessEntity.BusinessEntityID (it has a 1-to-1 relationship with "BusinessEntity" table, FirmName, rowguid and ModifiedDate columns ).
"Customer" which has the identity column "CustomerID" as Primary Key and column "FirmID" as Foreign Key to Firm .BusinessEntityID (plus CustomerName, rowguid and ModifiedDate columns).
i.e. (also see image)
tables: BusinessEntity Firm Customer
columns: CustomerID (PK)
BusinessEntityID(PK) --> BusinessEntityID (PK/FK) --> FirmID (FK)
What I'm trying to do is whenever a new Customer row is to be created:
A new BusinessEntity row to be created automatically and then pass its BusinessEntityID value to an (automatically) newly created Firm row which it turn would pass its own BusinessEntityID to Customer table as FirmID column.
As you can see a BusinessEntity row was no meaning unless it corresponds to a Firm (or other entities) and a Customer must include a Firm.
I created a view containing all three tables along with a trigger to do the job without success. Any suggestions?
The tables:
BusinessEntity
CREATE TABLE [dbo ].[BusinessEntity](
[BusinessEntityID] [int] IDENTITY(1,1) NOT NULL,
[rowguid] [uniqueidentifier] NOT NULL,
[ModifiedDate] [datetime] NOT NULL,
CONSTRAINT [PK_BusinessEntity_BusinessEntityID] PRIMARY KEY CLUSTERED
(
[BusinessEntityID] ASC
)
) ON [PRIMARY]
GO
ALTER TABLE [dbo].[BusinessEntity] ADD CONSTRAINT [DF_BusinessEntity_rowguid]
DEFAULT (newid()) FOR [rowguid]
GO
ALTER TABLE [dbo ].[BusinessEntity] ADD CONSTRAINT [DF_BusinessEntity_ModifiedDate]
DEFAULT (getdate()) FOR [ModifiedDate]
GO
Firm
CREATE TABLE [dbo].[Firm](
[BusinessEntityID] [int] IDENTITY(1,1) NOT NULL,
[FirmName] [nvarchar](30) NULL,
[rowguid] [uniqueidentifier] NOT NULL,
[ModifiedDate] [datetime] NOT NULL,
CONSTRAINT [PK_Firm_BusinessEntityID] PRIMARY KEY CLUSTERED
(
[BusinessEntityID] ASC
)
) ON [PRIMARY]
GO
ALTER TABLE [dbo].[Firm] ADD CONSTRAINT [DF_Firm_rowguid]
DEFAULT (newid()) FOR [rowguid]
GO
ALTER TABLE [dbo].[Firm] ADD CONSTRAINT [DF_Firm_ModifiedDate]
DEFAULT (getdate()) FOR [ModifiedDate]
GO
ALTER TABLE [dbo].[Firm] WITH CHECK ADD CONSTRAINT [FK_Firm_BusinessEntity_BusinessEntityID] FOREIGN KEY([BusinessEntityID])
REFERENCES [dbo].[BusinessEntity] ([BusinessEntityID])
GO
ALTER TABLE [dbo].[Firm] CHECK CONSTRAINT [FK_Firm_BusinessEntity_BusinessEntityID]
GO
Customer
CREATE TABLE [dbo].[Customer](
[CustomerID] [int] IDENTITY(1,1) NOT NULL,
[FirmID] [int] NULL,
[CustomerName] [nvarchar](28) NULL,
[rowguid] [uniqueidentifier] NOT NULL,
[ModifiedDate] [datetime] NOT NULL,
CONSTRAINT [PK_Customer_CustomerID] PRIMARY KEY CLUSTERED
(
[CustomerID] ASC
)
) ON [PRIMARY]
GO
ALTER TABLE [dbo].[Customer] ADD CONSTRAINT [DF_Customer_rowguid]
DEFAULT (newid()) FOR [rowguid]
GO
ALTER TABLE [dbo].[Customer] ADD CONSTRAINT [DF_Customer_ModifiedDate]
DEFAULT (getdate()) FOR [ModifiedDate]
GO
ALTER TABLE [dbo].[Customer] WITH CHECK ADD CONSTRAINT [FK_Customer_Firm_FirmID] FOREIGN KEY([FirmID])
REFERENCES [dbo].[Firm] ([BusinessEntityID])
GO
ALTER TABLE [dbo].[Customer] CHECK CONSTRAINT [FK_Customer_Firm_FirmID]
GO
Something weird happens here. I created this stored procedure:
CREATE PROCEDURE [dbo].[CreateFirmCustomer](#FirmName NVARCHAR(30), #CustomerName NVARCHAR(28)) AS
BEGIN;
SET NOCOUNT ON;
BEGIN TRANSACTION;
INSERT BusinessEntity DEFAULT VALUES;
DECLARE #BusinessEntityID INT = SCOPE_IDENTITY();
SET IDENTITY_INSERT [dbo].[Firm] ON
INSERT Firm(BusinessEntityID, FirmName)
VALUES (#BusinessEntityID, #FirmName);
SET IDENTITY_INSERT [dbo].[Firm] OFF
INSERT Customer(FirmID, CustomerName)
VALUES (#BusinessEntityID, #CustomerName);
DECLARE #CustomerID INT = SCOPE_IDENTITY();
SELECT #BusinessEntityID AS FirmID, #CustomerID AS CustomerID;
COMMIT;
END;
GO
When I run it sometimes the CustomerID column gets the value of BusinessEntityID column when it should really be independently auto-generated. Also the BusinessEntityID column auto-generates weird values e.g. jumped from value 7 to value 1002. (BusinessEntityID is BusinessEntity.BusinessEntityID ) Any clues? (see picture)
Now I created this view to insert Customers as Firms:
CREATE VIEW [dbo].[vBusEntityFirmCustomer]
AS
SELECT dbo.Firm.FirmName, dbo.Customer.CustomerName
FROM dbo.BusinessEntity INNER JOIN
dbo.Firm ON dbo.BusinessEntity.BusinessEntityID = dbo.Firm.BusinessEntityID INNER JOIN
dbo.Customer ON dbo.Firm.BusinessEntityID = dbo.Customer.FirmID
GO
And this trigger on the view:
CREATE TRIGGER [dbo].[trg_FirmCustomer]
ON [dbo].[vBusEntityFirmCustomer]
INSTEAD OF INSERT
AS
exec [dbo].[CreateFirmCustomer]
GO
But every time I enter a new FirmName CustomerName to insert a new row I get this message (see image):
Procedure or function 'CreateFirmCustomer' expects parameter '#FirmName', which was not supplied.
The fact is that I do supply FirmName.
Logically, as designed, you have to create a BusinessEntity first, then a Firm, then a Customer. Across all these tables, the only real information you're storing is the firm name and the customer name -- all the rest is derived and autogenerated by the database. We can encapsulate the operation CreateCustomer in a stored procedure:
CREATE PROCEDURE CreateCustomer(#FirmName NVARCHAR(30), #CustomerName NVARCHAR(28)) AS
BEGIN;
SET NOCOUNT ON;
BEGIN TRANSACTION;
INSERT BusinessEntity DEFAULT VALUES;
DECLARE #BusinessEntityID INT = SCOPE_IDENTITY();
INSERT Firm(BusinessEntityID, FirmName)
VALUES (#BusinessEntityID, #FirmName);
INSERT Customer(FirmID, CustomerName)
VALUES (#BusinessEntityID, #CustomerName);
DECLARE #CustomerID INT = SCOPE_IDENTITY();
-- Return IDs of the newly created rows as the result set
SELECT #BusinessEntityID AS FirmID, #CustomerID AS CustomerID;
COMMIT;
END;
Invoke as (for example) EXEC CreateCustomer 'Firm', 'Customer'. With the table definitions as given, this will fail because Firm.BusinessEntityID is an IDENTITY -- if it is to take its value from BusinessEntity, it shouldn't be. (You can work around this with IDENTITY_INSERT, but in a properly designed database this shouldn't be necessary.)
Another thing that's obviously weird is that we insert no business data at all in BusinessEntity (which is why we need the DEFAULT VALUES syntax) -- it's nothing but a super-general container of IDs, so it's of dubious value. Nevertheless, this demonstrates the general technique of inserting rows in multiple tables that have dependencies.
As written, this stored procedure always creates a new Firm and BusinessEntity to go along with the Customer. Logically, a Firm can have more than one Customer, so you probably want another stored procedure to create a Customer for an existing Firm. This is simpler, as it's just an INSERT in Customer with the appropriate FirmID. You may wish to have a separate CreateFirm stored procedure that you call first, followed by a CreateCustomer to add a customer for that firm.
According to me,
it all depend how and when those 3 tables are populated.
Suppose those three table are populated using single UI, then
I will write them in single proc within one transaction.
Suppose those 3 table will be will populated at diff stage i.e diff UI then i write them in diff proc as you have already define constraint.
BTW what is the purpose of rowguid in all 3 tables.

How to manage an ImportHistory in a Database?

I have a table ImportHistory in which I store history of importation. (Each time the user upload a file I store a row).
CREATE TABLE [dbo].[ImportHistory]
(
[Id] INT IDENTITY (1, 1) NOT NULL,
[Date] TIMESTAMP NOT NULL,
CONSTRAINT [PK_ImportHistory] PRIMARY KEY ([Id])
)
And I have also
CREATE TABLE [dbo].[Sales] (
[Id] VARCHAR (150) NOT NULL,
...
[ImportHistoryId] INT NOT NULL,
...
CONSTRAINT [FK_Sales_ImportHistory] FOREIGN KEY ([ImportHistoryId]) REFERENCES [dbo].[ImportHistory] ([Id])
);
The question is how to properly take the ID of ImportHistory and store it each time I insert a line in SALES for this import session ?
You insert a row in ImportHistory.
You SELECT SCOPE_IDENTITY() to get the ID of the newly created record.
You insert your Sales records, using the value acquired in Step 2 as the ImportHistoryID.
PS: The timestamp data type is not what you think it is. You probably want to use date or datetime2 instead.

two digit year as primary key in sql server

I have a table with these columns:
ID int,
d date
Now what I need is to define the primary key in such a way that ID would be unique for each year; meaning that there can not be two same IDs in 2004, but it is possible to have two same IDs in two different years.
Like:
insert into myTable values(1, '1-1-2004'), (1, '1-1-2005')
but not like:
insert into myTable values(1, '3-1-2005'), (1, '1-1-2005')
I tried this:
primary key(ID, datepart(YY, d))
but I get syntax error.
One way of doing this, if you can alter the table structure, is to add a persisted computed column for the year part, and then add a primary key for (id, computer_col), like this:
CREATE TABLE myTable (
id INT NOT NULL,
d DATE NOT NULL,
y AS DATEPART(YEAR,d) PERSISTED NOT NULL,
PRIMARY KEY(id,y)
)
I'm not saying this is a good solution in any way, but it should work. Using a trigger on insert or a check constraint might be better.
Using your test data this will allow the first insert statement, but disallow the second as it violates the primary key constraint.

Calculate a column from a table depending on different column from another tablecomputed column based on different

I have tables:
create table Aprovizionari
(
ID_Aprovizionare int identity(1,1) primary key,
CodCarte char(3) foreign key references Carti(CodCarte),
CodLibrarie char(3) foreign key references Librarii(CodLibrarie),
DataAprovizionare date default getdate(),
Cantitate int default 1
)
create table Returnari
(
CodRet char(3) primary key,
CodCarte char(3) foreign key references Carti(CodCarte),
CodLibrarie char(3) foreign key references Librarii(CodLibrarie),
CodEditura char(4) foreign key references Edituri(CodEditura),
DataRet date,
Cantitate int
)
I have a trigger that decrement the column Cantitate(Quantity) from Aprovizionari(Supply) while I add in Cantitate from another table Facturi(Invoices).
In Returnari(Returns -of books) I should have:
DataRet date,--this should be =DataAprovizionare+3 mounths
Cantitate int--this should be=the remaining Cantitate(Quantity) from Aprovizionari at date=DataAprovizionare+3 mounts
To do this you're going to need to check every day for Aprovizionari records that are 3 months old. When you find one you'll INSERT the Returnari record.
To do this you've got to create a stored procedure that when executed will create the Returnari records and then schedule a SQL Server Agent job to execute the procedure every day.
The stored procedure will look something like:
CREATE PROCEDURE YourDailyProc ( #Date DATE )
AS
INSERT INTO Returnari (CodCarte, CodLibrarie, DataRet, Cantitate)
SELECT CodCarte, CobLibrarie, CAST(#Date AS DATE), Cantitate
FROM Aprovizionari
WHERE DataAprovizionare = CAST(DATEADD(MONTH, -3, #Date) AS DATE)
GO
It's not clear where you'd get CodEditura but presumably you just need to join to another table.
Now you need a job to execute EXEC YourDailyProc #Date=CURRENT_TIMESTAMP each day. This answer looks like it has all the information you'll need to do that - how to schedule a job for sql query to run daily?

Resources