Computed column is not allowed to be used in another computed-column -- how can I allow it - sql

CREATE TABLE [dbo].[tbl_Marks](
[ID] [int] IDENTITY(1,1) NOT NULL,
[SID] [int] NOT NULL FOREIGN KEY REFERENCES tbl_Student(ID),
[Year] [char](1) NOT NULL,
[ExamType] [char](5) NOT NULL,
[S1] [int] null constraint s1_marks check (s1 >=0 and s1<=25),
[S2] [int] null constraint s2_marks check (s2 >=0 and s2<=25),
[S3] [int] null constraint s3_marks check (s3 >=0 and s3<=25),
[S4] [int] null constraint s4_marks check (s4 >=0 and s4<=25),
[S5] [int] null constraint s5_marks check (s5 >=0 and s5<=25),
[TotalMarks] AS (S1+S2+S3+S4+S5),
[Avg] AS ((S1+S2+S3+S4+S5)/5),
[Percentage] AS (((S1+S2+S3+S4+S5)/125.0)*100),
[Rank] [tinyint] NULL,
[Grade] [char](1) NULL,
[CreatedBy] [varchar](25) NULL,
[CreatedOn] [datetime] NULL,
[ModifiedBy] [varchar](25) NULL,
[ModifiedOn] [datetime] NULL,
[Remarks] [varchar](500) NULL
CONSTRAINT [PK_tbl_Marks] PRIMARY KEY CLUSTERED([ID] ASC)
);
I created the about table and I want to display the Grade based on the Percentage and I created the Function for that and I dropped the existing column name is "Grade" and I Re-added the column "Grade" using alter command
ALTER TABLE tbl_marks DROP COLUMN Grade
ALTER TABLE tbl_Marks ADD Grade AS dbo.fn_CalculateGrade(percentage)
While adding the "Grade" column I got this error is:
Msg 1759, Level 16, State 0, Line 47
Computed column 'Percentage' in table 'tbl_Marks' is not allowed to be used in another computed-column definition.
This is my function:
CREATE FUNCTION dbo.fn_CalculateGrade(#Percentage DECIMAL)
RETURNS VARCHAR(10)
AS
BEGIN
-- Declare the return variable here
DECLARE #Grade VARCHAR(10)
SET #Grade = (CASE WHEN ISNULL(#Percentage,0) BETWEEN 60.00 AND 70.99 THEN 'D'
WHEN ISNULL(#Percentage,0) BETWEEN 71.00 AND 80.99 THEN 'C'
WHEN ISNULL(#Percentage,0) BETWEEN 81.00 AND 90.99 THEN 'B'
WHEN ISNULL(#Percentage,0) BETWEEN 91.00 AND 100.00 THEN 'A' END)
RETURN #Grade
END
GO
AND I try to add with out function also that query is:
UPDATE tbl_Marks SET Grade= (CASE WHEN ISNULL(Percentage,0) BETWEEN 60.00 AND 70.99 THEN 'D'
WHEN ISNULL(Percentage,0) BETWEEN 71.00 AND 80.99 THEN 'C'
WHEN ISNULL(Percentage,0) BETWEEN 81.00 AND 90.99 THEN 'B'
WHEN ISNULL(Percentage,0) BETWEEN 91.00 AND 100.00 THEN 'A' END)
How can I achieve this with out an any error?

Related

SQL Server: select records, not linked to another table

I have a table:
CREATE TABLE [dbo].[CollectionSite]
(
[SiteCode] [nvarchar](32) NOT NULL,
[AddressId] [int] NOT NULL,
[RemittanceId] [int] NULL,
// additional columns
)
and a linked table:
CREATE TABLE [dbo].[CollectionSiteAddress]
(
[Id] [int] IDENTITY(1,1) NOT NULL,
[Name] [nvarchar](255) NULL,
[Address1] [nvarchar](255) NULL,
[Address2] [nvarchar](255) NULL,
[City] [nvarchar](128) NULL,
[State] [nvarchar](64) NULL,
[Zip] [nvarchar](32) NULL,
)
Relationship between these 2 tables:
ALTER TABLE [dbo].[CollectionSite] WITH CHECK
ADD CONSTRAINT [FK_CollectionSite_CollectionSiteAddress_AddressId]
FOREIGN KEY([AddressId]) REFERENCES [dbo].[CollectionSiteAddress] ([Id])
GO
ALTER TABLE [dbo].[CollectionSite] WITH CHECK
ADD CONSTRAINT [FK_CollectionSite_CollectionSiteAddress_RemittanceId]
FOREIGN KEY([RemittanceId]) REFERENCES [dbo].[CollectionSiteAddress] ([Id])
GO
I want to select all records from CollectionSiteAddress, which are not linked to CollectionSite (neither AddressId nor RemittanceId). Which request should I use?
I tried:
SELECT *
FROM CollectionSiteAddress
LEFT JOIN CollectionSite ON CollectionSiteAddress.Id = CollectionSite.AddressId
OR CollectionSiteAddress.Id = CollectionSite.RemittanceId
but it selects all records from CollectionSiteAddress
You are missing this WHERE clause:
WHERE CollectionSite.[SiteCode] IS NULL
because you want all the unmatched rows of CollectionSiteAddress.
I used the column [SiteCode] to check if it is NULL because it is not nullable in the definition of the table.
So you can write your query like this (shortened with aliases):
SELECT csa.*
FROM CollectionSiteAddress csa LEFT JOIN CollectionSite cs
ON csa.Id = cs.AddressId OR csa.Id = cs.RemittanceId
WHERE cs.[SiteCode] IS NULL
Or use NOT EXISTS:
SELECT csa.*
FROM CollectionSiteAddress csa
WHERE NOT EXISTS (
SELECT 1
FROM CollectionSite cs
WHERE csa.Id = cs.AddressId OR csa.Id = cs.RemittanceId
)

SQL unique column based on other columns

I have a SQL Server database table that I am trying to fix without having to resort to using the front end code to determine if the name of the institute is unique. I am setting up a Linq to SQL code base for all of the inserts.
here is the new table that I am trying to setup:
CREATE TABLE [dbo].[institution]
(
[institutionID] [int] IDENTITY(1,1) NOT NULL PRIMARY KEY,
[typeID] [tinyint] NOT NULL REFERENCES [dbo].[institutiontype]([institutiontypeID]),
[name] [varchar](255) NOT NULL UNIQUE,
[cityID] [int] NULL REFERENCES [dbo].[city]([cityID]),
[stateID] [int] NULL REFERENCES [dbo].[stateprovince]([stateID]),
[countryID] [int] NULL REFERENCES [dbo].[country]([countryID]),
[createby] [int] NOT NULL REFERENCES [dbo].[ipamuser]([ipamuserID]),
[createdatetime] [datetime] NOT NULL DEFAULT (GETDATE()),
[modifyby] [int] NULL REFERENCES [dbo].[ipamuser]([ipamuserID]),
[modifydatetime] [datetime] NULL,
[dataversion] [int] NOT NULL DEFAULT (0)
)
The issue is, the institutionname needs to be unique ONLY when the cityID, stateID and the countryID are the same. Setting up the table with the institutename as unique will not satisfy the needs since there are times when the same name can exist in different, cities, states or countries.
How would I resolve this
You need to write a complex constraint in your table. Define a user-defined-function which returns true (1 in BIT) if your required condition is satisfied and false otherwise.
Put this constraint in the table schema with a CHECK constraint.
CREATE FUNCTION dbo.fnIsNameUnique (
#name [varchar](255),
#cityID int,
#stateID int,
#countryID int,
)
RETURNS tinyint
AS
BEGIN
DECLARE #Result tinyint
IF EXISTS(SELECT * FROM institution WHERE name = #name AND cityID = #cityID AND stateID = #stateID AND countryID = #countryID)
SET #Result= 0
ELSE
SET #Result= 1
RETURN #Result
END
CREATE TABLE [dbo].[institution]
(
[institutionID] [int] IDENTITY(1,1) NOT NULL PRIMARY KEY,
[typeID] [tinyint] NOT NULL REFERENCES [dbo].[institutiontype]([institutiontypeID]),
[name] [varchar](255) NOT NULL UNIQUE,
[cityID] [int] NULL REFERENCES [dbo].[city]([cityID]),
[stateID] [int] NULL REFERENCES [dbo].[stateprovince]([stateID]),
[countryID] [int] NULL REFERENCES [dbo].[country]([countryID]),
[createby] [int] NOT NULL REFERENCES [dbo].[ipamuser]([ipamuserID]),
[createdatetime] [datetime] NOT NULL DEFAULT (GETDATE()),
[modifyby] [int] NULL REFERENCES [dbo].[ipamuser]([ipamuserID]),
[modifydatetime] [datetime] NULL,
[dataversion] [int] NOT NULL DEFAULT (0),
CONSTRAINT ckValidName CHECK (
dbo.fnIsNameUnique(name, cityID, stateID, countryID) = 1)
)
)
I don't know why you need anything so complex, just putting a UNIQUE constraint or index on ([name], CityID, StateID, CountryID) does what you say you need.

SQL Check Constraint with User Defined Function

I am troubleshooting an issue seen in our sql server database recently.
Table 1 has a calculated bit column based off of a user defined function which checks if a record exists in another table and evaluates to 0 if not.
Table 2 is the table searched by the function for Table 1. Table 2 also has a check constraint using a function to see if the bit field in Table 1 is set to 1.
This seems like a circular dependency. The problem is that when inserting a batch of records into Table 2, the constraint fails. Inserting these same records 1 by 1 allows all of the inserts to go through. I can't for the life of me figure out why batch inserts cause it to fail. Any help is appreciated.
CREATE TABLE [dbo].[tPecosPriceCheckStoreSubcategory](
[PecosPriceCheckID] [int] NOT NULL,
[StoreID] [int] NOT NULL,
[SubcategoryID] [int] NOT NULL,
[UndirectedExpectedScans] [int] NULL,
[PriceMin] [decimal](8, 2) NULL,
[PriceMax] [decimal](8, 2) NULL,
[PastPriceVariancePercent] [decimal](5, 2) NULL,
[ChangeDate] [datetime] NOT NULL,
[IsUndirected] [bit] NOT NULL,
[IsDirected] AS ([dbo].[fnPecosPriceCheckStoreSubcategoryIsDirected]([PecosPriceCheckID],[SubcategoryID])),
CONSTRAINT [PK_tPecosPriceCheckStoreSubcategory] PRIMARY KEY CLUSTERED
(
[PecosPriceCheckID] ASC,
[StoreID] ASC,
[SubcategoryID] ASC
)
ALTER TABLE [dbo].[tPecosPriceCheckStoreSubcategory] ADD CONSTRAINT [DF_IsUndirected] DEFAULT ((0)) FOR [IsUndirected]
GO
CREATE FUNCTION [dbo].[fnPecosPriceCheckStoreSubcategoryIsDirected]
(
#PecosPriceCheckID int,
#SubcategoryID int
)
RETURNS bit
AS
BEGIN
declare #isDirected bit
set #isDirected = 0
if (exists (select 1 from tPecosDirectedPriceCheckItem where PecosPriceCheckID = #PecosPriceCheckID and SubcategoryID = #SubcategoryID ))
begin
set #isDirected = 1
end
return #isDirected
END
CREATE TABLE [dbo].[tPecosDirectedPriceCheckItem](
[ID] [int] IDENTITY(1,1) NOT NULL,
[PecosPriceCheckID] [int] NOT NULL,
[PecosItemID] [int] NOT NULL,
[ItemSortOrder] [int] NOT NULL,
[SubcategoryID] [int] NOT NULL,
[ChangeDate] [datetime] NULL,
CONSTRAINT [PK_tPecosDirectedPriceCheckItem] PRIMARY KEY CLUSTERED
(
[ID] ASC
)
ALTER TABLE [dbo].[tPecosDirectedPriceCheckItem] WITH NOCHECK ADD CONSTRAINT [CK_tPecosDirectedPriceCheckItem_CheckPriceCheckSubcategoryDirected] CHECK (([dbo].[fnCheckDirectedItemPriceCheckSubcategory]([PecosPriceCheckID],[SubcategoryID])=(0)))
GO
ALTER TABLE [dbo].[tPecosDirectedPriceCheckItem] CHECK CONSTRAINT [CK_tPecosDirectedPriceCheckItem_CheckPriceCheckSubcategoryDirected]
GO
CREATE FUNCTION [dbo].[fnCheckDirectedItemPriceCheckSubcategory]
(
#PriceCheckID INT,
#SubcategoryID INT
)
RETURNS BIT
AS
BEGIN
DECLARE #isViolation BIT
SET #isViolation =
CASE WHEN EXISTS (SELECT * FROM tPecosPriceCheckStoreSubcategory WHERE SubcategoryID = #SubcategoryID AND PecosPriceCheckID = #PriceCheckID AND IsDirected = 1)
THEN
0
ELSE
1
END
RETURN #isViolation
END

CHECK CONSTRAINT ERROR USING SQL MANAGEMENT STUDIO

CREATE TABLE [dbo].[SALES]
(
[SaleID] [uniqueidentifier] NOT NULL DEFAULT NEWID(),
[ProductID] [int] NOT NULL,
[WorkID] [int] NOT NULL,
[Quantity] [smallint] NOT NULL,
[SaleDate] [datetime] NOT NULL CONSTRAINT DF_SaleDate DEFAULT (GETDATE())
CONSTRAINT CHK_QuantitySaleDate CHECK (Quantity > 0 AND DATEDIFF (d,GETDATE(), SaleDate) <=0)
) ON [PRIMARY]
Trying to execute the above query results in the following error:
"Column CHECK constraint for column 'SaleDate' references another column, table 'SALES'."
Can someone please enlighten me?
It's because you are setting constraint as COLUMN constraint. You have to set it as TABLE constraint. So, after:
[SaleDate] [datetime] NOT NULL CONSTRAINT DF_SaleDate DEFAULT (GETDATE())
you need a comma sign, so it should be:
[SaleDate] [datetime] NOT NULL CONSTRAINT DF_SaleDate DEFAULT (GETDATE()),
CONSTRAINT...

How can you define a computed column like this?

I have an Equipment table in SQL Server 2008 like this:
CREATE TABLE [dbo].[Equipment](
[EquipmentID] [nchar](10) NOT NULL,
[EquipmentName] [nchar](50) NOT NULL,
[ProducedDate] [date] NOT NULL,
[WarrantyPeriod] [int] NOT NULL,
[SerialNumber] [nchar](20) NOT NULL,
[BrandID] [tinyint] NOT NULL,
CONSTRAINT [PK_Equipment] PRIMARY KEY CLUSTERED
)
I want to have a computed column WarrantyStatus that will return either Unexpired or Expired when calculating, based on columns ProducedDate and WarrantyPeriod.
This is wrong, but it's what I want:
ALTER TABLE [dbo].[Equipment]
ADD [WarrantyStatus] AS IIF(DATEDIFF(MONTH, [ProducedDate], GETDATE()) < [WarrantyPeriod], "Unexpired", "Expired")
Try:
ALTER TABLE [dbo].[Equipment]
ADD [WarrantyStatus] AS
case when DATEDIFF(MONTH, [ProducedDate], GETDATE()) < [WarrantyPeriod]
then 'Unexpired'
else 'Expired'
end