Doing validation in stored procedure if data already exist - sql-server-2005

I want to create a stored procedure where I want to check if I add a Bin no and if exist in the table it should give me validation message otherwise it should work
I tried like below but it is not working
ALTER PROCEDURE [dbo].[sp_P_WMS_Stock_Adj_Val_Proc]
(#Bin_no nvarchar(max))
AS BEGIN
IF (#Bin_no = )
BEGIN
RAISERROR('Bin no already exist', 16, 1)
RETURN
END
ELSE
BEGIN
SELECT DISTINCT
Location_Name + '-' + convert(varchar, mkey)
FROM
WMS_Storage_Bin
WHERE
status = 'Confirmed'
AND location_name = #Bin_no
END
END
I am using SQL Server 2005.

If you really must do this in a stored procedure - then use this:
ALTER PROCEDURE dbo.ValidateWMSStock
(#Bin_no nvarchar(max))
AS BEGIN
IF EXISTS (SELECT * FROM dbo.WMS_Storage_Bin
WHERE location_name = #Bin_no)
BEGIN
RAISERROR('Bin no already exist', 16, 1)
RETURN
END
ELSE
BEGIN
SELECT DISTINCT
Location_Name + '-' + convert(varchar, mkey)
FROM
WMS_Storage_Bin
WHERE
status = 'Confirmed'
AND location_name = #Bin_no
END
END
But as Mitch Wheat already said - it's probably much easier to just put a unique constraint on that column:
ALTER TABLE dbo.WMS_Storage_Bin
ADD CONSTRAINT UQ_Location_Name UNIQUE(location_name)
Once the unique constraint is in place, if you attempt to insert a row with a location_name that already exists, you'll get an error
Msg 2627, Level 14, State 1, Line xx
Violation of UNIQUE KEY constraint 'UQ_Location_Name'. Cannot insert duplicate key in object 'dbo.WMS_Storage_Bin'. The duplicate key value is (......).
Update:
I tried this - I believe the code I provided works just fine:
DECLARE #BinTable TABLE (ID INT NOT NULL, Location_Name NVARCHAR(100))
INSERT INTO #BinTable VALUES(1, N'A1112'), (2, N'A1113'), (3, N'A1114'), (4, N'A1121')
DECLARE #Bin_No NVARCHAR(MAX)
-- SET #Bin_No = N'A1112' -- this prints "Bin already exists" as expected
SET #Bin_No = N'A4112' -- this prints "Bin does *NOT* exist" as expected
IF EXISTS (SELECT * FROM #BinTable WHERE location_name = #Bin_no)
PRINT 'Bin already exists'
ELSE
PRINT 'Bin does *NOT* exist'

Related

Checking if name already exists and also type of name in SQL Server

I am checking for if name exist in the stored procedure. So basically checking if attr_name exists in the ibui_attribute table.
Here the attr_name can be either of the two types. There is column in the table called is_group that tells you if the attribute is a group or an attribute. I need to throw the error accordingly and hence written and if else condition. Do I need to write a query again to check if the attribute is group or an attribute for the if else condition or can I do that in the if exist SQL statement that has been written
CREATE PROCEDURE [IBT].[save_ibui_attribute]
#p_attr_id INT = NULL,
#p_is_group BIT = 0,
#p_attr_name VARCHAR (20),
#p_attr_desc VARCHAR (250),
#p_parent_attr_id INT,
#p_attr_level VARCHAR (20),
#p_attr_data_type VARCHAR (8),
#p_last_updt_user_nm VARCHAR (30) = NULL,
#p_last_updt_dtime DATETIME = NULL,
#debug AS BIT = 0
AS
BEGIN
BEGIN TRY
SET NOCOUNT ON;
DECLARE
#logfile VARCHAR (MAX),
#msg VARCHAR (255);
SET #msg = 'IBT.save_ibui_attribute Starts';
IF #debug = 1
BEGIN
SELECT 'IBT.save_ibui_attribute DEBUG START';
END;
IF #p_attr_id IS NULL
BEGIN
IF EXISTS (SELECT attr_name
FROM IBT.ibt_attribute
WHERE UPPER(attr_name) = UPPER(#p_attr_name))
BEGIN
IF ATTRIBUTE
RAISERROR ( 50001, 16, 1, 'ERROR! : New attribute has a name that is already in use. Please use a different attribute name' );
ELSE
IF GROUP
RAISERROR (50001, 16, 1, 'ERROR! : New group has a name that is already in use. Please use a different group name' );
END;
END;
END;
Do I do something like this
declare #isGroup bit;
IF #p_attr_id IS NULL
BEGIN
SET #isGroup = (SELECT is_group
FROM IBT.ibt_attribute
WHERE UPPER(attr_name) = UPPER(#p_attr_name))
IF #isGroup = 0
RAISERROR ( 50001, 16, 1, 'ERROR! : New attribute has a name that is aleady in use. Please use a different attribute name' );
ELSE IF #isGroup = 1
RAISERROR ( 50001, 16, 1, 'ERROR! : New group has a name that is aleady in use. Please use a different group name' );
END;
END;

Subquery returns more than one value?

I'm trying to use a stored procedure I wrote that is supposed to create a new project in a "Project" table. It also checks to see if there is a saved project in a "Saved Project" table with the same ID and deletes it upon successful creation.
It's also supposed to check whether the user_id passed has permission to actually create a project( i.e. isn't a standard user).
Here is the stored procedure:
USE [BugMate_DB]
GO
/****** Object: StoredProcedure [dbo].[create_project] Script Date: 2020-07-08 11:05:30 AM ******/
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
ALTER PROCEDURE [dbo].[create_project]
#project_name NVARCHAR(40),
#date_started DATETIME,
#project_description NVARCHAR(400),
#project_status NVARCHAR(40),
#project_active BIT,
#next_iteration_date DATETIME,
#created_by_userid INT,
#project_leader_id INT,
#save_id INT = NULL
AS
SET NOCOUNT ON
BEGIN
IF (SELECT TOP 1 roleid from user_info WHERE userid = #created_by_userid) = 'SDU'
BEGIN
RAISERROR ('User does not have permission to do this action. Please contact a manager or administrator to resolve this issue.', 16, 1)
END
ELSE
BEGIN
INSERT INTO project(project_name, date_started, project_description, project_status, project_active, next_iteration_date, created_by_userid, project_leader_id)
VALUES (#project_name, #date_started, #project_description, #project_status, #project_active, #next_iteration_date, #created_by_userid, #project_leader_id)
IF ##ERROR <> 0
BEGIN
RAISERROR('Project creation insert failed.', 16, 1)
END
ELSE
BEGIN
IF #save_id != NULL
BEGIN
IF EXISTS (SELECT TOP 1 save_id FROM saved_project WHERE save_id = #save_id)
BEGIN
DELETE FROM saved_project WHERE save_id = #save_id
END
END
END
END
IF ##ERROR <> 0
BEGIN
RAISERROR('Error creating project', 16, 1)
END
ELSE
BEGIN
INSERT INTO project_member(userid, project_number)
VALUES (#created_by_userid, (SELECT project_number FROM project WHERE created_by_userid = #created_by_userid))
END
END
The problem is that I am getting this error when execute my SP:
Msg 512, Level 16, State 1, Procedure create_project, Line 48
Subquery returned more than 1 value. This is not permitted when the subquery follows =, !=, <, <= , >, >= or when the subquery is used as an expression.
I'm not sure why any of my sub queries would be returning multiple values.
Here are the values I am trying to pass:
USE [BugMate_DB]
GO
DECLARE #return_value int
EXEC #return_value = [dbo].[create_project]
#project_name = N'Test',
#date_started = N'12/25/2015 12:00:00 AM',
#project_description = N'This is a test.',
#project_status = N'InDevelopment',
#project_active = 1,
#next_iteration_date = N'12/25/2015 12:00:00 AM',
#created_by_userid = 19,
#project_leader_id = 19,
#save_id = NULL
SELECT 'Return Value' = #return_value
GO
I have tried using "TOP 1" to try and get a single value back but it doesn't seem to be what I'm looking for.
As far as I can tell this isn't an issue of joins either.
I'm new to SQL Server so any help would be appreciated.
Try changing this
IF ( SELECT TOP 1 roleid from user_info WHERE userid = #created_by_userid ) = 'SDU'
BEGIN
RAISERROR ( 'User does not have permission to do this action. Please contact a manager or administrator to resolve this issue.', 16, 1 )
END
To
IF NOT EXISTS ( SELECT * FROM user_info WHERE userid = #created_by_userid AND roleid = 'SDU' )
BEGIN
RAISERROR ( 'User does not have permission to do this action. Please contact a manager or administrator to resolve this issue.', 16, 1 )
END
Edit: Include explicit role access.
IF NOT EXISTS ( SELECT * FROM user_info WHERE userid = #created_by_userid AND roleid IN ( 'SDU', 'MNG', 'ADM ' ) )
BEGIN
RAISERROR ( 'User does not have permission to do this action. Please contact a manager or administrator to resolve this issue.', 16, 1 )
END
Update:
USE [BugMate_DB]
GO
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
ALTER PROCEDURE [dbo].[create_project]
#project_name NVARCHAR(40),
#date_started DATETIME,
#project_description NVARCHAR(400),
#project_status NVARCHAR(40),
#project_active BIT,
#next_iteration_date DATETIME,
#created_by_userid INT,
#project_leader_id INT,
#save_id INT = NULL
AS
BEGIN
SET NOCOUNT ON;
DECLARE #err INT = 0;
DECLARE #output TABLE ( project_number INT );
IF NOT EXISTS ( SELECT * FROM user_info WHERE userid = #created_by_userid AND roleid IN ( 'SDU', 'MNG', 'ADM ' ) )
BEGIN
RAISERROR ( 'User does not have permission to do this action. Please contact a manager or administrator to resolve this issue.', 16, 1 );
END
ELSE
BEGIN
INSERT INTO project (
project_name, date_started, project_description, project_status, project_active, next_iteration_date, created_by_userid, project_leader_id
)
OUTPUT inserted.project_number INTO #output
VALUES (
#project_name, #date_started, #project_description, #project_status, #project_active, #next_iteration_date, #created_by_userid, #project_leader_id
);
-- Capture error value.
SET #err = ##ERROR;
IF #err <> 0
BEGIN
RAISERROR ( 'Project creation insert failed.', 16, 1 );
END
ELSE
BEGIN
IF #save_id IS NULL
BEGIN
IF EXISTS ( SELECT * FROM saved_project WHERE save_id IS NULL )
BEGIN
DELETE FROM saved_project WHERE save_id IS NULL;
END
END
END
END
IF #err <> 0
BEGIN
RAISERROR ( 'Error creating project', 16, 1 );
END
ELSE
BEGIN
INSERT INTO project_member (
userid, project_number
)
VALUES (
#created_by_userid,
( SELECT project_number FROM #output )
);
END
END
Please compare the NULL values using IS NULL like below:
IF #save_id IS NULL
or
IF #save_id IS NOT NULL
I haven't seen this type of query before
INSERT INTO project_member(userid, project_number)
VALUES (#created_by_userid,
(SELECT project_number FROM project WHERE created_by_userid = #created_by_userid))
I would do either
INSERT INTO project_member(userid, project_number)
VALUES (#created_by_userid, #project_id)
if I were just inserting 2 values.
If inserting many values I would do SELECT and not VALUES.
If I were inserting maybe more that 1 row of values:
INSERT INTO project_member(userid, project_number)
SELECT created_by_userid, project_number FROM project
WHERE created_by_userid = #created_by_userid
Im just guessing since that is about line 46
Also, what sacse said about IF (#save_id IS NULL)
maybe there is an answer in there someplace

Bulk insert from csv file - Ignore rows with errors - SQL Server

I am trying to import data from a csv file to SQL Server. There are thousands of entries in the csv file and we have a lot of rows with incorrect data in it.
Some of the rows in the CSV File are:
`"ID"|"EmpID"|"FName"|"LName"|"Gender"|"DateOfBirth"
"1"|"90043041961"|"ABCD"|"TEST"|"F"|"1848-05-05 00:00:00.000"
"1"|"10010161961"|"XYZ"|"TEST"|"F"|"1888-12-12 00:00:00.000"
.
.
..
..
....
"4"|"75101141821PPKKLL"|"LLKK"|"F"|"1925-09-09 00:00:00.000"|""
"4"|"32041401961UUYYTT"|"PPLL"|"M"|"1920-01-01 00:00:00.000"|""
.
.....
"25"|"00468132034"|"FGTT"|"OOOO"|"F"|"1922-11-11 00:00:00.000"
"25"|"00468132034"|"KKKK"|"PPPP"|"F"|"1922-11-11 00:00:00.000"
Creating the TestTable and trying to insert data (from csv file) into it:
create table TestTable
(
ID varchar(5),
EmpID varchar(25),
FName varchar(25),
LName varchar(25),
Gender varchar(5),
DateOfirthB varchar(30)
);
I am using the following script to import data from csv file to the TestTable in SQL Server:
bulk insert TestTable
from 'C:\TestData.csv'
with
(firstrow = 2,
DATAFILETYPE='char',
FIELDTERMINATOR= '"|"',
ROWTERMINATOR = '\n',
ERRORFILE ='C:\ImportErrors.csv',
MAXERRORS = 0,
TABLOCK
);
Errors:
Msg 4863, Level 16, State 1, Line 1
Bulk load data conversion error (truncation) for row 32763, column 5 (Gender).
Msg 4863, Level 16, State 1, Line 1
Bulk load data conversion error (truncation) for row 32764, column 5 (Gender).
Is there any way to ignore the rows (in the csv file) which can not be added for some or other reason and insert the one's which have the correct syntax?
Thanks
PS: I can not use SSIS. Only allowed to use SQL
I deal with different CSV Files that I receive from different sources on a weekly basis, so of the data is nice and clean and others are a nightmare. So this is how I handle the CSV Fields I receive, I hope it helps you. You will still need to add some data validation to handle malformed data.
SET NOCOUNT ON
GO
-- Create Staging Table
IF OBJECT_ID(N'TempDB..#ImportData', N'U') IS NOT NULL
DROP TABLE #ImportData
CREATE TABLE #ImportData(CSV NVARCHAR(MAX))
-- Insert the CSV Data
BULK INSERT #ImportData
FROM 'C:\TestData.csv'
-- Add Control Columns
ALTER TABLE #ImportData
ADD ID INT IDENTITY(1, 1)
ALTER TABLE #ImportData
ADD Malformed BIT DEFAULT(0)
-- Declare Variables
DECLARE #Deliminator NVARCHAR(5) = '|', #ID INT = 0, #DDL NVARCHAR(MAX)
DECLARE #NumberCols INT = (SELECT LEN(CSV) - LEN(REPLACE(CSV, #Deliminator, '')) FROM #ImportData WHERE ID = 1)
-- Flag Malformed Rows
UPDATE #ImportData
SET Malformed = CASE WHEN LEN(CSV) - LEN(REPLACE(CSV, #Deliminator, '')) != #NumberCols THEN 1 ELSE 0 END
-- Create Second Staging Table
IF OBJECT_ID(N'TestTable', N'U') IS NOT NULL
DROP TABLE TestTable
CREATE table TestTable
(ID varchar(4000),
EmpID varchar(4000),
FName varchar(4000),
LName varchar(4000),
Gender varchar(4000),
DateOfirthB varchar(4000));
-- Insert CSV Rows
WHILE(1 = 1)
BEGIN
SELECT TOP 1
#ID = ID
,#DDL = 'INSERT INTO TestTable(ID, EmpID, FName, LName, Gender, DateOfirthB)' + CHAR(13) + CHAR(10) + REPLICATE(CHAR(9), 1)
+ 'VALUES' -- + CHAR(13) + CHAR(10) + REPLICATE(CHAR(9), 2)
+ '(' + DDL + ')'
FROM
(
SELECT
ID
,DDL = '''' + REPLACE(REPLACE(REPLACE(CSV, '''', ''''''), #Deliminator, ''','''), '"', '') + ''''
FROM
#ImportData
WHERE
ID > 1
AND Malformed = 0) D
WHERE
ID > #ID
ORDER BY
ID
IF ##ROWCOUNT = 0 BREAK
EXEC sp_executesql #DDL
END
-- Clean Up
IF OBJECT_ID(N'TempDB..#ImportData', N'U') IS NOT NULL
DROP TABLE #ImportData
-- View Results
SELECT * FROM dbo.TestTable
Since the OP stated "[...] insert the the one's which have the correct syntax", I wonder why nobody suggested to modify the MAXERRORS clause. Despite not all errors can be masqueraded, it works well for conversion ones.
Therefore, my suggestion is using MAXERRORS=999 in place of MAXERRORS=0 (as per orinal example).

SQL Server: auto-generated custom format sequence number

I am working with Microsoft SQL Server 2014. In our requirement, custom formatted sequence number is include.
The sequence number format is CAT-YYYY-MM-NNNNNN. Sample data:
CAT-2016-10-000001
CAT-2016-10-000002
.
.
.
CAT-2016-10-999999
I don't want to use GUID or any other and I want to work with a procedure or function.
So, I am trying with this:
CREATE TABLE [category]
(
[id] int NOT NULL UNIQUE IDENTITY,
[category_no] nvarchar(20) NOT NULL,
[category_name] nvarchar(50) NOT NULL,
PRIMARY KEY ([id])
);
CREATE FUNCTION generate_category_no()
RETURNS CHAR(20)
AS
BEGIN
DECLARE #category_no CHAR(20)
SET #category_no = (SELECT MAX(category_no) FROM category)
IF #category_no IS NULL
SET #category_no = 'CAT-' + YEAR(getDate()) + '-' + MONTH(getDate()) + '-000001'
DECLARE #no int
SET #no = RIGHT(#category_no,6) + 1
RETURN 'CAT-' + YEAR(getDate()) + '-' + MONTH(getDate()) + '-' + right('00000' + CONVERT(VARCHAR(10),#no),6)
END
GO
ALTER TABLE category DROP COLUMN category_no;
ALTER TABLE category ADD category_no AS dbo.generate_category_no();
INSERT INTO category (category_name)
VALUES ('BMW'), ('JAGUAR');
When I run the above SQL in step-by-step, it is OK. It shown no error. But when I run the following command:
SELECT * FROM category;
it shows the following error:
Msg 217, Level 16, State 1, Line 1
Maximum stored procedure, function, trigger, or view nesting level exceeded (limit 32).
I don't know how to solve this one. And even I don't know my function has worked or not. I referenced from internet for this function.
ADDED
I need to reset sequence no for every month. Eg. for next month, no should be as follow:
CAT-2016-11-000001
Please, enlighten me. Thanks in advance!
Modify your function as below
ALTER TABLE category DROP COLUMN category_no;
alter FUNCTION dbo.generate_category_no( #id int)
RETURNS CHAR(20)
AS
BEGIN
RETURN 'CAT-' + cast(YEAR(getDate()) as varchar(10)) + '-' + cast(MONTH(getDate()) as varchar(10))+ '-' + right('00000' + CONVERT(VARCHAR(10),#id),6)
END
ALTER TABLE category ADD category_no AS dbo.generate_category_no(id);
INSERT INTO category
(category_name)
VALUES
('BMW13'),
('JAGUAR');
SELECT * FROM category will give the below result.
1 BMW CAT-2016-10-000001
2 JAGUAR CAT-2016-10-000002
3 BMW1 CAT-2016-10-000003
4 BMW13 CAT-2016-10-000004
Try this:
To initialize your new field:
ALTER TABLE category DROP COLUMN category_no;
ALTER TABLE category ADD category_no CHAR(20)
UPDATE category set category_no = dbo.generate_category_no()
For other insert:
CREATE TRIGGER [dbo].[category_i]
ON [dbo].[category]
AFTER INSERT
AS BEGIN
UPDATE category
SET category_no = dbo.generate_category_no()
FROM inserted
WHERE category.pk = inserted.pk
END
But you can try to use SEQUENCE feature, available on Sql Server by 2012 version
About SEQUENCE you can see here
Biggest flaw in your function is it will not work for Batch Insert's
Since you have ID auto generated, here is a easier way to do this
category_no AS Concat('CAT-', Year(Getdate()), '-', Month(Getdate()), '-', RIGHT(Concat('00000', id), 6))
Demo
CREATE TABLE #seq
(
id INT IDENTITY(1, 1),
name VARCHAR(10),
category_no AS Concat('CAT-', Year(Getdate()), '-', Month(Getdate()), '-', RIGHT(Concat('00000', id), 6))
)
INSERT INTO #seq
(name)
VALUES ('val')
Result :
id name category_no
-- ---- -----------
1 val CAT-2016-10-000001
Finally, I solved the problem. My Function look like as follow:
CREATE FUNCTION generate_category_no()
RETURNS CHAR(20)
AS
BEGIN
DECLARE #category_no CHAR(20)
SET #category_no = (SELECT MAX(category_no) FROM category WHERE category_no LIKE CONCAT('CAT-', YEAR(getDate()), '-', MONTH(getDate()), '-%'))
IF #category_no is null SET #category_no = CONCAT('CAT-', YEAR(getDate()), '-', MONTH(getDate()), '-000000')
DECLARE #no INT
SET #no = RIGHT(#category_no,6) + 1
RETURN CONCAT('CAT-', YEAR(getDate()), '-', MONTH(getDate()), '-', RIGHT('00000' + CONVERT(VARCHAR(10),#no),6))
END
GO
And I insert data as follow:
INSERT INTO category (category_no, category_name) VALUES (dbo.generate_category_no(),'BMW');
INSERT INTO category (category_no, category_name) VALUES (dbo.generate_category_no(),'JAGUAR');
One things is that We can call function from INSERT query.
So, when I run the following sql:
SELECT * FROM category;
It give the result as shown in below.
+---+--------------------+--------------+
|id |category_no |category_name |
+---+--------------------+--------------+
| 1 |CAT-2016-10-000001 | BMW |
| 2 |CAT-2016-10-000002 | JAGUAR |
+---+--------------------+--------------+
Thanks everybody for helping me. Thanks!!!

SQL Alter table within an IF ELSE statement

I have the following sql:
DECLARE #Variable1 VARCHAR(10)
SET #Variable1 = 'YES
IF #Variable1 = 'YES'
BEGIN
alter table #Tempfile add Newcolumn varchar(10)
UPDATE #Tempfile
SET Newcolumn ='J'
FROM #Tempfile
INNER JOIN OtherTable
ON #Tempfile.SPLPKD = OtherTable.SPLPKD
AND #Tempfile.SPLHNR = OtherTable.SPLHNR
PRINT('Variable was Yes')
END
ELSE
BEGIN
PRINT('Variable was NO!!')
END
Now as long as the #variable1 is YES everthing goes as expected.
But when #Variable1 is NO, I get the following error message:
Msg 207, Level 16, State 1, Line 201 Invalid column name 'Newcolumn'.
Which for me looks very strange cause the I thought the IF would prevent to check the code within that statement.
What am I doing wrong here?
Your extra column does not exist when you start executing the script, the UPDATE is being validated and decide that the column doesn't exists. This check can be avoided by using embedded sql:
IF #Variable1 = 'YES'
BEGIN
alter table #Tempfile add Newcolumn varchar(10)
EXECUTE('UPDATE #Tempfile
SET Newcolumn =''J''
FROM #Tempfile
INNER JOIN OtherTable
ON #Tempfile.SPLPKD = OtherTable.SPLPKD
AND #Tempfile.SPLHNR = OtherTable.SPLHNR
PRINT(''Variable was Yes'')')
END
ELSE
BEGIN
PRINT('Variable was NO!!')
END