Executing a stored procedure to populate a table column? - sql-server

Can I use the EXEC keyword to run a stored procedure to populate the QuestionScore column?
CREATE TABLE Question_Result
(
ResultID INT IDENTITY (10000, 1) NOT NULL,
QResultID VARCHAR (10) NOT NULL DEFAULT 'QRES' + CAST(NEXT VALUE
FOR non_identity_incrementer AS VARCHAR(10)),
QuestionScore DECIMAL (4,2) EXEC dbo.update_question_result_question_score(),
Assessment INT NULL,
DateTimeModified DATETIME NOT NULL DEFAULT SYSDATETIME(),
PRIMARY KEY CLUSTERED (ResultID),
FOREIGN KEY (Assessment) REFERENCES Assessment_Result (ResultID)
);
My stored procedure is:
CREATE PROCEDURE update_question_result_question_score (
#QuestionScore DECIMAL(4,2) OUTPUT,
#StudentAnswer NVARCHAR(MAX) OUTPUT,
#AssessingAnswer NVARCHAR(MAX) OUTPUT
)
AS
BEGIN
SELECT *
FROM StudentAnswerQuestionScore
SET #QuestionScore = (SELECT Score FROM StudentAnswerQuestionScore)
SET #StudentAnswer = (SELECT [Student Answer] FROM StudentAnswerQuestionScore)
SET #AssessingAnswer = (SELECT [Assessing Answer] FROM StudentAnswerQuestionScore)
IF (#StudentAnswer = #AssessingAnswer)
INSERT INTO Question_Result (QuestionScore)
VALUES (#QuestionScore)
END

You can try to use function for your computed column. Hopefully below codes can give you some ideas:
use staging
go
create table Question
(
QuestionKey int identity(1,1),
QuestionDesc varchar(50),
AssignedAnswer varchar(50),
Score int
)
go
insert into Question
select 'Capital city of AU', 'ACT', 10
go
create function ufnAssignScore (#Question varchar(50), #Answer varchar(50))
Returns int
as
BEGIN
declare #return int
select #return = Score
FROM Question
where QuestionDesc = #Question and AssignedAnswer = #Answer
return #return
END
go
create table Answer
(
AnswerKey int identity(1,1),
StudentID varchar(50),
QuestionDesc varchar(50),
AnswerDesc varchar(50),
Score as dbo.ufnAssignScore(QuestionDesc, AnswerDesc)
)
go
insert into Answer (StudentID, QuestionDesc, AnswerDesc)
select 'a1', 'Capital city of AU', 'Mel'
union all
select 'a2', 'Capital city of AU', 'ACT'
go
select * from Answer

Related

How to handle T-SQL missing columns when using OPENJSON function?

Consider the three T-SQL scenarios below:
-- scenario 1: SSN is specified with a value
DECLARE #Json_Array nvarchar(max) = '[{"Employee_ID":123,"Employee_Name":"John Doe","SSN":123456789}]';
SELECT *
FROM OPENJSON(#Json_Array)
WITH (Employee_ID int, Employee_Name nvarchar(60), SSN int)
-- scenario 2: SSN is specified with null for the value
SET #Json_Array = '[{"Employee_ID":123,"Employee_Name":"John Doe","SSN":null}]';
SELECT *
FROM OPENJSON(#Json_Array)
WITH (Employee_ID int, Employee_Name nvarchar(60), SSN int)
-- scenario 3: SSN is not specified
SET #Json_Array = '[{"Employee_ID":123,"Employee_Name":"John Doe"}]';
SELECT *
FROM OPENJSON(#Json_Array)
WITH (Employee_ID int, Employee_Name nvarchar(60), SSN int)
Both scenario 2 and 3 return a NULL value for SSN.
How can I determine if SSN was not included in the #Json_Array? The reason I need to do this is to avoid updating the employee's SSN to NULL if SSN is not included in the JSON.
The answer is to select [value] from OPENJSON(#json_item) where [key]='Column_Name'. Below is a full example.
-- create table of original data that will be modified
DECLARE #Json_Array_Original nvarchar(max) = '[
{"Employee_ID":123,"Employee_Name":"John Doe","SSN":123456789},
{"Employee_ID":124,"Employee_Name":"John Smith","SSN":343434343},
{"Employee_ID":125,"Employee_Name":"Jim Doe","SSN":515151515}
]';
declare #Original_Data table (Employee_ID int, Employee_Name nvarchar(20), SSN int);
insert into #Original_Data
select * from openjson(#Json_Array_Original)
with (Employee_ID int, Employee_Name nvarchar(20), SSN int)
select * from #Original_Data
-- create table of data changes that will be applied
DECLARE #Json_Array_Changes nvarchar(max) = '[
{"Employee_ID":123,"Employee_Name":"Jon Doe","SSN":null},
{"Employee_ID":124,"Employee_Name":"John Smythe"},
{"Employee_ID":125,"SSN":555151515}
]';
declare #Data_Changes table (Employee_ID int, Employee_Name nvarchar(20), SSN int);
insert into #Data_Changes
select * from openjson(#Json_Array_Changes)
with (Employee_ID int, Employee_Name nvarchar(20), SSN int)
select * from #Data_Changes
-- create table containing json records of data changes
declare #Json_Items table ([key] int, [value] nvarchar(max), type int);
insert into #Json_Items
select * from openjson(#Json_Array_Changes)
-- create table that specifies with a 1 the columns (properties) of each json record that have new values provided
declare #Json_Keys table (Employee_ID int, Employee_Name bit, SSN bit);
insert into #Json_Keys
select
json_value([value], '$.Employee_ID'),
(select 1 from openjson([value]) where [key]='Employee_Name'),
(select 1 from openjson([value]) where [key]='SSN')
from #Json_Items
select * from #Json_Keys
-- apply new values only for columns (properties) that have values specified
update od
set
od.Employee_Name = iif(jk.Employee_Name = 1, dc.Employee_Name, od.Employee_Name),
od.SSN = iif(jk.SSN = 1, dc.SSN, od.SSN)
from #Original_Data od
inner join #Data_Changes dc on od.Employee_ID = dc.Employee_ID
inner join #Json_Keys jk on dc.Employee_ID = jk.Employee_ID
select * from #Original_Data

"String or binary data would be truncated" error while updating but not when inserting new record

I understand that this error comes when we try to insert characters more than the capacity of column.
But what I am not able to understand is a recent output in which I was getting the error when updating in the table but not when a new record was getting inserted in the table with the same parameter size.
Table structrue:
Entity
(
#EntityID int,
#Name varchar(200),
#FullName varchar(50),
#ParentEntityID int,
#ShortDesc varchar(255),
#LongDesc varchar(2000)
)
When I am trying to insert a new row, it simply truncates the parameter who has value more than its size (here #FullName), but when I try to update the same values on an existing record, it simply throws the exception.
Why can't it just truncate here also?
Edit::
Procedure for update.
ALTER PROCEDURE [dbo].[Entity_Update]
#EntityID int,
#Name varchar(200),
#FullName varchar(410),
#ParentEntityID int,
#ShortDesc varchar(255),
#LongDesc varchar(2000)
AS
set nocount on;
update dbo.Entity set
Name = #Name,
FullName = #FullName,
ParentEntityID = #ParentEntityID,
ShortDesc = #ShortDesc,
LongDesc = #LongDesc,
DateUpdated = GETUTCDATE()
where EntityID = #EntityID;
return 0;
INSERT Procedure is :
ALTER PROCEDURE [dbo].[Entity_Insert]
#Name varchar(200),
#FullName varchar(410),
#ParentEntityID int,
#ShortDesc varchar(255),
#LongDesc varchar(2000),
#UserID int,
#EntityID int OUTPUT
AS
set nocount on;
set xact_abort on;
begin tran
insert dbo.Entity (
Name,
FullName,
ParentEntityID,
ShortDesc,
LongDesc,
RecordStatus,
DateUpdated)
values (#Name,
#FullName,
#ParentEntityID,
#ShortDesc,
#LongDesc,
1,
GETUTCDATE());
select #EntityID = SCOPE_IDENTITY();
CREATE TABLE Entity
(
EntityID INT IDENTITY
NOT NULL
PRIMARY KEY ,
Name VARCHAR(200) ,
FullName VARCHAR(50) ,
ParentEntityID INT ,
ShortDesc VARCHAR(255) ,
LongDesc VARCHAR(2000)
);
INSERT [Entity] ( [Name], [FullName], [ParentEntityID], [ShortDesc],
[LongDesc] )
VALUES ( 'Name', 'FullName', 0, 'Short', 'Long' );
UPDATE [Entity]
SET [LongDesc] = 'Here is an updated value'
WHERE [FullName] = 'FullName';
SELECT *
FROM [Entity] AS [e];
UPDATE [Entity]
SET [LongDesc] = LEFT('Yet another update ' + REPLICATE('blah ', 1000),
2000)
WHERE [FullName] = 'FullName';
SELECT *
FROM [Entity] AS [e];
Works perfectly well for me.

How to inserting data into multiple SQL tables and create unique ID for each values

As an example my database has 3 tables: People_Table, Address_Table and Gender_Table.
I want to insert
"First_Name", "Last_Name"
to the People_Table and
"Address_Line1", "Address_Line2", "City" & "Zip_Code"
to the Address_Table, and
"F" or "M"
to the Gender_Table.
For each entry I need to create a unique identifier with 8 character. The ID should look like this "N0000001", "N0000002", "N0000023"
How can I do this?
Thanks for your help!!!
You're making a mistake by making the database unique key the same as a visual business key.
You should instead use identity columns for your primary key (they autoincrement without any code required). Then you can create a calculated column on your table that for example turns the number 34563 into N0034563
What happens when your ID gets bigger than 9999999?
You need create a sequence table which have two columns number and tablegroupid. And you should create insert trigger. On trigger look sequence table for max number. And make them +1. Concatenate your prefix. And generate your custom identifier.
Here is one way to do this:
CREATE TABLES:
CREATE TABLE People_Table (
id_key VARCHAR(8)
,id INT
,firstname VARCHAR(50)
,lastname VARCHAR(50)
);
CREATE TABLE Address_Table (
id_key VARCHAR(8)
,Address_Line1 VARCHAR(50)
,Address_Line2 VARCHAR(50)
,City VARCHAR(50)
,Zip_Code VARCHAR(5)
);
CREATE TABLE Gender_Table (
id_key VARCHAR(8)
,Gender VARCHAR(1)
);
CREATE PROC:
Create a procedure to take your insert values as parameters and create separate insert statements for each table. Take max(id) from People_Table and increase by 1 before inserting it. To create your unique identifier key value, concatenate N and replication of 0's with your max(id) + 1.
CREATE PROCEDURE dbo.test_multipleinsert (
#FirstName VARCHAR(50)
,#LastName VARCHAR(50)
,#AddressLine1 VARCHAR(50)
,#AddressLine2 VARCHAR(50)
,#city VARCHAR(50)
,#zipcode VARCHAR(5)
,#gender VARCHAR(1)
)
AS
DECLARE #uniqueidentifier VARCHAR(8)
,#maxrowid INT;
SET NOCOUNT ON
BEGIN
SET #maxrowid = 0;
SELECT #maxrowid = max(id) + 1
FROM People_table;
SET #uniqueidentifier = 'N' + right(replicate(0, 7) + cast(#maxrowid AS VARCHAR(7)), 7);
INSERT INTO People_Table (
id_key
,id
,firstname
,lastname
)
VALUES (
#uniqueidentifier
,#maxrowid
,#firstName
,#lastName
);
INSERT INTO Address_Table (
id_key
,Address_Line1
,Address_Line2
,City
,Zip_Code
)
VALUES (
#uniqueidentifier
,#AddressLine1
,#AddressLine2
,#city
,#ZipCode
);
INSERT INTO Gender_Table (
id_key
,Gender
)
VALUES (
#uniqueidentifier
,#gender
);
END
EXECUTE PROC TO INSERT VALUES:
EXEC dbo.test_multipleinsert #FirstName = 'Michael'
,#LastName = 'Jordan'
,#AddressLine1 = '123 Main Street'
,#AddressLine2 = 'Apt#12'
,#City = 'CHICAGO'
,#ZipCode = '64601'
,#Gender = 'M';
EXEC dbo.test_multipleinsert #FirstName = 'Mark'
,#LastName = 'Johnson'
,#AddressLine1 = '456 Main Street'
,#AddressLine2 = 'Apt#89'
,#City = 'Atlanta'
,#ZipCode = '75859'
,#Gender = 'M';
SELECT *
FROM people_table;
SELECT *
FROM address_table;
SELECT *
FROM gender_table;
As a side note, your table is going to hit some major issues due to the your limitations on number of records you can have between 1 and 9999999 only.

In stored procedure if null value found it should skip that insert query

I have 2 tables one is
peson contains(personid Identity, firstname,Lastname,PlaceOfBirth,Gender)
and another
Education contains (Eduid identity, egreename,boardUniver,yearOfPassing,obtainedMarks, personid)
now my problem is that each person have more than 1 degree, but some have 1 or 2 degree, so how can i skip the insert queries?
First Table
Create table person(personid int Identity(1,1) primary key, firstname nvarchar(40), Lastname nvarchar(40), PlaceOfBirth nvarchar(40), Gender nvarchar(10))
Second Table
create table Education(Eduid int identity(1,1) primary key, Degreename nvarchar(40), boardUniver nvarchar(40), yearOfPassing nvarchar(40), obtainedMarks numeric(10,2), personid int,
constraint fk_eduPerson foreign key (personid) references person(personid))
Procedure to store information
Create procedure EmpDetails
(
#Firstname nvarchar(40), #Lastname nvarchar(40), #PlaceOfBirth nvarchar(40), #Gender nvarchar(8),
#Degreename0 int, #boardUniver0 nvarchar(40), #yearOfPassing0 nvarchar(20), #obtainedMarks0 int,
#Degreename1 int, #boardUniver1 nvarchar(40), #yearOfPassing1 nvarchar(20), #obtainedMarks1 int,
#Degreename2 int, #boardUniver2 nvarchar(40), #yearOfPassing2 nvarchar(20), #obtainedMarks2 int,
)
AS BEGIN
declare #personid int
INSERT INTO person(firstname,Lastname,PlaceOfBirth,Gender) values(#firstname,#Lastname,#PlaceOfBirth,#Gender)
SELECT #personid=##IDENTITY
if(#Degreename0 !=NULL)
BEGIN
INSERT INTO Education(Degreename,boardUniver,yearOfPassing,obtainedMarks, personid) values (#Degreename0,#boardUniver0,#yearOfPassing0,#obtainedMarks0, #personid)
END
IF(#Degreename1 !=null)
BEGIN
INSERT INTO Education(Degreename,boardUniver,yearOfPassing,obtainedMarks, personid) values (#Degreename1,#boardUniver1,#yearOfPassing1,#obtainedMarks1, #personid)
END
IF(#Degreename2!=null)
BEGIN
INSERT INTO Education(Degreename,boardUniver,yearOfPassing,obtainedMarks, personid) values (#Degreename2,#boardUniver2,#yearOfPassing2,#obtainedMarks2,#personid)
END
END
This is not working.. this inserts all rows empty.. is there any other solution to do this?
Please give suggestion if any other.. Thanks
Try IS NOT NULL instead of != NULL. In most relational databases, the comparison operators return false if either input is NULL, even if they both are. Here is a SQL Fiddle demonstrating the behavior.
(Sorry. That SQL Fiddle really works.)
Admittedly, this is confusing, as that fact should mean all your INSERTs are skipped. I don't see anything here that would insert empty rows.
Try this one -
Create procedure EmpDetails
(
...
)
AS BEGIN
DECLARE #personid INT
INSERT INTO Person (firstname, Lastname, PlaceOfBirth, Gender)
SELECT #firstname, #Lastname, #PlaceOfBirth, #Gender
SELECT #personid = SCOPE_IDENTITY()
INSERT INTO Education (Degreename, boardUniver, yearOfPassing, obtainedMarks, PersonID)
SELECT a = #Degreename0, b = #boardUniver0, c = #yearOfPassing0, d = #obtainedMarks0, e = #personid
WHERE #Degreename0 IS NOT NULL
UNION ALL
SELECT #Degreename1, #boardUniver1, #yearOfPassing1, #obtainedMarks1, #personid
WHERE #Degreename1 IS NOT NULL
UNION ALL
SELECT #Degreename2, #boardUniver2, #yearOfPassing2, #obtainedMarks2, #personid
WHERE #Degreename2 IS NOT NULL
END

Get highest value of a column in a stored procedure in SQLServer

I have the following stored procedure in SQL Server
IF OBJECT_ID ('kii.p_CreateSection') IS NOT NULL
DROP PROCEDURE kii.p_CreateSection
GO
CREATE PROCEDURE kii.p_CreateSection
#Name AS NVARCHAR(200),
#DocumentId AS INT,
#TypeId AS INT = NULL,
#ReportId AS INT = NULL,
#OrdinalPosition AS SMALLINT
AS
INSERT INTO kii.Section (Name, DocumentId, TypeId, ReportId, OrdinalPosition)
VALUES (#Name, #DocumentId, #TypeId, #ReportId, #OrdinalPosition)
SELECT SCOPE_IDENTITY();
GO
GRANT EXECUTE on kii.p_CreateSection TO p_role_kii
GO
The table Section is related to Document. Each document has several sections and they're ordered by the OrdinalPosistion value.
I'd like to test that if the given value for #OrdinalPosition is 0, then set it at the maximum value of all the sections of this Document +1.
Insert kii.Section( Name, DocumentId, TypeId, ReportId, OrdinalPosition )
Select #Name, #DocumentId, #TypeId, #ReportId
, Case
When #OrdinalPosition <> 0 Then #OrdinalPosition
Else (
Select Max( OrdinalPosition ) + 1
From kii.Section
Where DocumentId = #DocumentId
)
End

Resources