Table-Valued Function using IF statement in SQL Server - sql

I have a Student table consists of following parameters
[ID] [nvarchar](50) NOT NULL,
[Firsname] [nvarchar](50) NOT NULL,
[Lastname] [nvarchar](50) NOT NULL,
[Melicode] [nchar](10) NOT NULL,
[City] [nvarchar](50) NOT NULL,
[Province] [nvarchar](50) NOT NULL,
[Active] [int] NULL
i want to write a Table-Valued Function named Show which has one parameter as number. the function will act as following
if #number = 1 , returns all columns from Student table
if #number = 2 , returns only City from Student
if #number = 3 , returns only Province from Student
i wrote the following T-SQL, but it only works for (if (#number = 1)). When the user enter #number as 2 or 3, the function does not work. Thank You
Create function Show(#number int)
RETURNS #result TABLE
(
[ID] [nvarchar](50) NOT NULL,
[Firsname] [nvarchar](50) NOT NULL,
[Lastname] [nvarchar](50) NOT NULL,
[Melicode] [nchar](10) NOT NULL,
[City] [nvarchar](50) NOT NULL,
[Province] [nvarchar](50) NOT NULL,
[Active] [int] NULL
)
AS
BEGIN
IF (#number = 1)
INSERT INTO #result SELECT * from Student
IF (#number = 2)
INSERT INTO #result (City) values ((SELECT City from Student))
IF (#number = 3)
INSERT INTO #result (Province) values ((SELECT Province from Student))
RETURN -- #Players (variable only required for Scalar functions)
END
go
select *from dbo.show(1)

This is not going to work:
INSERT INTO #result (City)
VALUES ((SELECT City from Student))
Either you have all the values as scalar SQL variables, or literals - then you can use
INSERT INTO #result (City)
VALUES ('New York')
INSERT INTO #result (City)
VALUES (#ChosenCity)
or you have a SELECT statement to fill the values - then you need this syntax:
INSERT INTO #result (City)
SELECT City
FROM Student
without the VALUES keyword. And as #GiorgiNakeuri correctly states - this will then fail because all your columns require a value (have the NOT NULL attribute), so this insert cannot succeed - you need to provide all NOT NULL values (or define a default value for each column)

CREATE FUNCTION dbo.Show
(
#number INT
)
RETURNS #result TABLE
(
ID NVARCHAR(50),
Firsname NVARCHAR(50),
Lastname NVARCHAR(50),
Melicode NCHAR(10),
City NVARCHAR(50),
Province NVARCHAR(50),
Active INT
)
AS
BEGIN
IF (#number = 1)
INSERT INTO #result
SELECT * FROM dbo.Student
IF (#number = 2)
INSERT INTO #result (City)
SELECT City FROM dbo.Student
IF (#number = 3)
INSERT INTO #result (Province)
SELECT Province FROM dbo.Student
RETURN
END
GO
SELECT * FROM dbo.Show(2)

the table returned is dictated by how the result table was declared. the query below works (in a sense) but the results include all the columns with NULLs for those columns not targeted by the #number parameter:
CREATE TABLE dbo.z_Show (str1 VARCHAR(10), str2 VARCHAR(10), str3 VARCHAR(10))
INSERT z_show
SELECT 1, 1, 1 UNION ALL
SELECT 2, 2, 2 UNION ALL
SELECT 3, 3, 3
CREATE FUNCTION dbo.Show(#number int)
RETURNS #result TABLE
(
--[ID] [nvarchar](50) NOT NULL,
--[Firsname] [nvarchar](50) NOT NULL,
--[Lastname] [nvarchar](50) NOT NULL,
--[Melicode] [nchar](10) NOT NULL,
--[City] [nvarchar](50) NOT NULL,
--[Province] [nvarchar](50) NOT NULL,
--[Active] [int] NULL
str1 VARCHAR(10), str2 VARCHAR(10), str3 VARCHAR(10)
)
AS
BEGIN
--for debugging|start
--DECLARE #number INT = 3
--DECLARE #result TABLE (str1 VARCHAR(10), str2 VARCHAR(10), str3 VARCHAR(10))
--for debugging|end
IF (#number = 1)
BEGIN
--PRINT ('IF (#number = 1)')
INSERT INTO #result SELECT * from dbo.z_Show
END
IF (#number = 2)
BEGIN
--PRINT ('IF (#number = 2)')
INSERT INTO #result (str2) SELECT str2 from dbo.z_Show
END
IF (#number = 3)
BEGIN
--PRINT ('IF (#number = 3)')
INSERT INTO #result (str3) SELECT str3 from dbo.z_Show
END
RETURN -- #Players (variable only required for Scalar functions)
END
SELECT 'number 1 was passed', *
FROM dbo.show(1)
SELECT 'number 2 was passed', *
FROM dbo.show(2)
SELECT 'number 3 was passed', *
FROM dbo.show(3)

You mentioned #result has all NOT NULL columns. If you want to insert only city into that #result, it will take remaining columns as Null so that's why an error happened. You don't mention that #result columns are NOT NULL columns and one more is. Remove VALUES keyword from the INSERT statement because it is inserting with a Select statement

The insert statements for cases 2 and 3 are incorrect. No need for VALUES keyword when inserting values coming from a select statement.

Related

How to insert data in multiple tables using single query in SQL Server?

I'm trying to insert data into multiple tables if it doesn't already exist. I can't seem to figure this out at all.
Table 1:
CREATE TABLE [dbo].[search_results]
(
[company_id] [int] NULL,
[title] [text] NULL,
[link] [text] NULL,
[domain] [text] NULL,
[index] [int] NULL,
[id] [int] PRIMARY KEY IDENTITY(1,1) NOT NULL
)
Table 2:
CREATE TABLE [dbo].[statements]
(
[statement_link_id] [int] NULL,
[statement_page] [text] NULL,
[statement_text_location] [text] NULL,
[statement_description] [text] NULL,
[statement_description_html] [text] NULL,
[statement] [int] NULL,
[id] [int] PRIMARY KEY IDENTITY(1,1) NOT NULL
)
This is what I want to do:
check to see if the company_id and the link already exist in the table or not.
SELECT *
FROM search_results
WHERE company_id = 4 AND link = 'https://test.com';
If the data does not exist, insert it into two tables
INSERT INTO search_results (company_id, link, title, domain)
VALUES (4, 'https://test.com', 'title', 'test.com');
and also insert the search_result last inserted id to the following table. corporate_statement value is always 1
INSERT INTO corporate_statements (statement_link_id, corporate_statement)
VALUES (743, 1);
I'm trying this based on what I found on SO
DECLARE #result AS TABLE (id int, company_id int, link text, title text, domain text);
WITH cte AS
(
SELECT *
FROM (VALUES (4, 'https://test.com', null, null)) AS t(company_id, link, title, domain)
)
INSERT INTO #result
SELECT *
FROM
(INSERT INTO dbo.search_results (company_id, link, title, domain)
OUTPUT inserted.*
SELECT * FROM cte
WHERE NOT EXISTS (SELECT * FROM dbo.[search_results]
WHERE company_id = cte.company_id
AND CAST(link AS varchar(250)) = CAST(cte.link AS varchar(50))
)) r
SELECT * FROM #result;
Even trying with a single insert statement, I get the following error:
Msg 213, Level 16, State 1, Line 8
Column name or number of supplied values does not match table definition.
As you can see, I also tried to cast it to varchar since it was throwing error when I hadn't. How can update this?
To me - this seems a lot cleaner, and it also will be a lot simpler to understand (and maintain!) in the future:
-- check to see if your data already exists
IF NOT EXISTS (SELECT *
FROM search_results
WHERE company_id = 4 AND link = 'https://test.com')
BEGIN TRY
BEGIN TRANSACTION
-- if not -> insert into the first table
INSERT INTO search_results (company_id, link, title, domain)
VALUES (4, 'https://test.com', 'title', 'test.com');
-- grab the last identity value from that previous INSERT
DECLARE #LastId INT;
SELECT #LastId = SCOPE_IDENTITY();
-- insert into the second table
INSERT INTO corporate_statements (statement_link_id, corporate_statement)
VALUES (#LastId, 1);
COMMIT;
END TRY
BEGIN CATCH
-- in case of an error rollback the full transaction
ROLLBACK;
END CATCH;
and you're done. Or am I missing something? I think this would be doing what you're described in the intro of your post - not necessarily what you're showing in your code...

replace a computed column with a logic that works with INSERT

I have a table called tblPacks.
CREATE TABLE [dbo].[tblPacks]
(
[ID] [int] NOT NULL,
[BatchNumber] [varchar](30) NULL,
[PackID] VARCHAR(50),
[Status] [int] NULL
)
And a stored procedure spInsertPacks.
CREATE PROCEDURE spInsertPacks
#ID INT,
#BatchNumber VARCHAR(30),
#Count INT
AS
BEGIN
INSERT INTO tblPacks
Values
(
#ID,
#BatchNumber,
CONVERT([varchar](50),
'PK'+
case
when len(#ID)<=(3) then CONVERT([varchar](20),right((0.001)*#ID,(3)),0)
else CONVERT([varchar](20),#ID,0)
end,0),0)
END
If ID of data type INT inserted in an order like 1,2,3,4,5... the above logic works fine. But there is no restriction for a user to enter random numbers. I want a stored procedure to generate PackID(PK001,PK002..) sequence in order, irrespective of #ID and ID. Cannot be an identity Column. How can I do that?
Actually This PackID is a barcode If barcode already existed for Pack then that sequence may not be same with the sequence we used and Newly generated barcodes which we are generating will be in seuquence PK001
Sample Output:-
ID BatchNumber PackID Status
1 b1 PK001 0
1 b2 Pk002 0
5 b7 ABC768 0
3 b2 PK003 0
I have simplified the logic a bit for generating PackID
Add a new column(identifier) for identifying the code and use it for PackID generation and for sequence use Identity column
CREATE TABLE [dbo].[tblPacks]
(
Iden_ID INT IDENTITY(1, 1),
[ID] [INT] NOT NULL,
[BatchNumber] [VARCHAR](30) NULL,
[Identifier] [VARCHAR](50),
[PackID] AS [Identifier]
+ CASE
WHEN Iden_ID <= 999 THEN RIGHT('00' + CONVERT(VARCHAR(3), ID), 3)
ELSE CONVERT([VARCHAR](20), ID, 0)
END,
[Status] [INT] NULL
)
To check the working
INSERT INTO [dbo].[tblPacks]
([ID],identifier,[BatchNumber],[Status])
VALUES (1,'pk','bat',1)
SELECT *
FROM [tblPacks]

Insert Data Into three joined tables using a stored procedure

I have three tables [PublicationNotice], [PublicationNoticeClient] and [PublicationNoticeInvoice].
Table1 have one-to-one relation with table2 and table3.
I am using a stored procedure to insert data into the tables. My form consists of all attributes from table1, table2 and table3.
My problem is, when I Submit data into these three tables it inserts all data accept table2_id and table3_id in table1.
HINT: I am using ASP .Net and MSSQL
My stored procedure looks like this:
CREATE procedure [dbo].[AddUpdatePublicationNotice]
#ID bigint = NULL,
#Title varchar(max)= NULL,
#NewspaperName varchar(50) =NULL,
#Cities varchar(max)= NULL,
#PublicationSize varchar(8) =NULL,
#PublicationDate date =NULL,
#PublicationType varchar(50)= NULL,
#NewspaperPageNo smallint= NULL,
#Colored bit= NULL,
#CaseNature varchar(15)= NULL,
#ImagePath varchar(max)= NULL,
#ClientId bigint =NULL,
#InvoiceId bigint= NULL,
#CreatedById bigint = NULL,
#EditedById bigint= NULL,
#EditedDate datetime =NULL,
--******************************************--
#ClientName varchar(max)= NULL,
#ClientType varchar(50)= NULL,
#ClientContactPerson varchar(max)= NULL,
#ClientAddress varchar(max)= NULL,
#ClientCity varchar(50) =NULL,
#ClientCountry varchar(50)= NULL,
--******************************************--
#InvoiceDate date= NULL,
#InvoiceTotalAmount bigint= NULL,
#InvoicePaymentRecievedDate date= NULL,
#InvoiceChequeNo bigint= NULL,
#InvoiceBankName varchar(50)= NULL
--******************************************--
AS
Insert into PublicationNotice (
[Title]
,[NewspaperName]
,[Cities]
,[PublicationSize]
,[PublicationDate]
,[PublicationType]
,[NewspaperPageNo]
,[Colored]
,[CaseNature]
,[ImagePath]
,[ClientId]
,[InvoiceId]
,CreatedById
)Values(
#Title
,#NewspaperName
,#Cities
,#PublicationSize
,#PublicationDate
,#PublicationType
,#NewspaperPageNo
,#Colored
,#CaseNature
,#ImagePath
,#ClientId
,#InvoiceId
,#CreatedById)
insert into [dbo].[PublicationNoticeClient] (
[Name]
,[Type]
,[ContactPerson]
,[Address]
,[City]
,[Country]
,[CreatedById])
Values(#ClientName
,#ClientType
,#ClientContactPerson
,#ClientAddress
,#ClientCity
,#ClientCountry
,#CreatedById)
Insert Into [dbo].[PublicationNoticeInvoice] (
[Date]
,[TotalAmount]
,[PaymentRecievedDate]
,[ChequeNo]
,[BankName]
,[CreatedById])
Values (
#InvoiceDate
,#InvoiceTotalAmount
,#InvoicePaymentRecievedDate
,#InvoiceChequeNo
,#InvoiceBankName
,#CreatedById)
GO
I know I can first insert table2 and table3 values and then select the last inserted values from table2 and table3 (that are table2_id and table3_id) and then insert them into table1
Is there any other fast way to insert data like this ???
You can use ##IDENTITY , SCOPE_IDENTITY, IDENT_CURRENT or OUTPUT methods to retrieve last ID. The Output is the only secure one.
You need to insert into a table variable first and then query it
create table table1(
id int identity(1,1),
id_table2 int,
id_table3 int);
create table table2 (
id int identity(100,1),
val varchar(20));
create table table3 (
id int identity(200,1),
val varchar(20));
declare #varTable2 table (LastID int);
declare #varTable3 table (LastID int);
insert into table2
output inserted.id into #varTable2 values ('a');
insert into table3
output inserted.id into #varTable3 values ('a');
insert into table1 (id_table2, id_table3) values
( (select LastID from #varTable2),
(select LastID from #varTable3)
);
select * from table1
--You need to declare two variables to get identity values from table 2 and table 3 As
DECLARE #table2_identity AS INT
DECLARE #table3_identity AS INT
--After insert in Table 2 set table2_identity variable as follows
SET #table2_identity = SELECT SCOPE_IDENTITY()
--After insert in Table 3 set table3_identity variable as follows
SET #table3_identity = SELECT SCOPE_IDENTITY()
--Then assign those variable values in insert query of Table 1

user defined function return statment in Scalar-Valued

I have a table with the following columns:
CREATE TABLE [dbo].[TblPerson](
[Id] [int] IDENTITY(1,1) NOT NULL,
[name] [nvarchar](30) NULL,
[Family] [nvarchar](40) NULL,
[address] [nvarchar](200) NULL,
[MeliCode] [char](10) NOT NULL,
[IsActive] [bit] NULL CONSTRAINT [DF_TblPerson_IsActive] DEFAULT ((0)),
[Count] [int] NULL CONSTRAINT [DF_TblPerson_Count] DEFAULT ((0)),
CONSTRAINT [PK_TblPerson] PRIMARY KEY CLUSTERED
(
Now i want to write a UDF which gets the Melicode as input parameter and if the IsActive = 1 then the UDF returns the value of count, else the UDF must return 0.
i write the following function as
CREATE FUNCTION ReturnMelli ( #Melicode CHAR(10) )
RETURNS INT
AS
BEGIN
DECLARE #RESULT BIT
SET #RESULT = ( SELECT Isactive
FROM TblPerson
WHERE MeliCode = #Melicode
)
DECLARE #R INT
SET #R = ( SELECT [Count]
FROM TblPerson
WHERE MeliCode = #Melicode
)
IF ( #RESULT = 1 )
BEGIN
RETURN #R
END
ELSE
BEGIN
RETURN 0
END
END
Then, there is problem with running the UDF as
Msg 455, Level 16, State 2, Procedure ReturnMelli, Line 17
The last statement included within a function must be a return statement.
i don't get the reason of failure. Even i put the return value at the end, it doesn't work
Replace this
IF ( #RESULT = 1 )
BEGIN
RETURN #R
END
ELSE
BEGIN
RETURN 0
END
with this
RETURN IIF(#RESULT = 1, #R, 0)
This link will Help you
Try like this ..
CREATE FUNCTION ReturnMelli ( #Melicode CHAR(10) )
RETURNS INT
AS
BEGIN
DECLARE #RESULT BIT
SET #RESULT = ( SELECT Isactive
FROM TblPerson
WHERE MeliCode = #Melicode
)
DECLARE #R INT
SET #R = ( SELECT [Count]
FROM TblPerson
WHERE MeliCode = #Melicode
)
IF ( #RESULT <> 1 )
BEGIN
SET #R =0
END
RETURN #R
END

Insert multiple records using stored procedure

I have two tables
emplyoee (first table)
id primary key auto increment
emp_name varchar
student(second table)
id foriegnkey emplyoee.id
st_name varchar
I want to insert multiple student records for a single employeeid . My code is attached here , but this use to only one student record update. How can I write stored procedure for this need.
I am new with SQL server and stored procedure.
Could you please help me?
create procedure empst_Sp
#emp_name varchar(50),
#st_name varchar(50)
as
begin
insert into emplyoee (emp_name) values (#emp_name)
insert into student(id,st_name) values(SCOPE_IDENTITY(),#st_name)
end
For your case, you can try this code above ( I'm using XML parameter type)
CREATE PROCEDURE EmployeeIns
#EmployeeName NVARCHAR(50),
#Students XML
AS
/*
#Students : <Students>
<Student Name='Studen 1'/>
<Student Name='Studen 1'/>
</Students>
*/
BEGIN
DECLARE #StudenTable TABLE(Name NVARCHAR(50))
DECLARE #EmployeeId INT
INSERT INTO #StudenTable
SELECT Tbl.Col.value('#Name', 'NVARCHAR(50)')
FROM #Students.nodes('//Student') Tbl(Col)
INSERT INTO Emplyoee VALUES(#EmployeeName)
SET #EmployeeId = SCOPE_IDENTITY()
INSERT INTO Student
SELECT #EmployeeId, Name FROM #StudenTable
END
Update 1 :
Your table design should be look like this :
CREATE TABLE [dbo].[Emplyoee](
[Id] [int] IDENTITY(1,1) NOT NULL,
[Name] [nvarchar](150) NULL,
CONSTRAINT [PK_Emplyoee] PRIMARY KEY CLUSTERED
(
[Id] ASC
))
CREATE TABLE [dbo].[Student](
[EmployeeId] [int] NULL,
[Name] [nvarchar](150) NULL,
[Id] [int] IDENTITY(1,1) NOT NULL,
CONSTRAINT [PK_Student] PRIMARY KEY CLUSTERED
(
[Id] ASC
))
The execute code :
EXEC EmployeeIns #EmployeeName='trungtin1710', #Students = '<Students><Student Name="Studen 1"/><Student Name="Studen 1"/></Students>'
All you need is a local variable in which you can set the value retrieved from Scope_Identity:-
CREATE PROCEDURE empst_Sp
#emp_name varchar(50),
#st_name varchar(50)
AS
BEGIN
DECLARE #id INT
INSERT INTO emplyoee (emp_name) VALUES (#emp_name)
set #id = SCOPE_IDENTITY()
INSERT INTO student(id,st_name) VALUES (#id,#st_name)
END
As I understand:
If emplyoee with #emp_name is already exists then insert student records with ID of the emplyoee, if there is not any emplyoee with #emp_name then need to insert new emplyoee and student with ID of the new emplyoee. Yes?
CREATE PROCEDURE empst_Sp
#emp_name varchar(50),
#st_name varchar(50)
AS
BEGIN
DECLARE #EmplyoeeId int
SET #EmplyoeeId = NULL
select #EmplyoeeId = id
from emplyoee
where emp_name = #emp_name
IF #EmplyoeeId IS NULL
BEGIN
insert into emplyoee (emp_name) values (#emp_name)
SET #EmplyoeeId = SCOPE_IDENTITY()
END
insert into student(id, st_name) values(#EmplyoeeId, #st_name)
END