Null values stored in table via Stored Procedure - sql-server

Following is my stored procedure which stores data in two tables namely SuccessfulLogins and FailedLogins
ALTER procedure [dbo].[Proc_CheckUser]
#UserID VARCHAR(50),
#Password VARCHAR(50)
AS
SET NOCOUNT ON
DECLARE #ReturnVal VARCHAR(500)
DECLARE #PasswordOld VARCHAR(50)
DECLARE #Type NVARCHAR(50)
DECLARE #IP NVARCHAR(50)
SELECT #PasswordOld = Password,#Type=ClientType,#IP=IPAddress
FROM Clients
WHERE Username = #userid
IF (#PasswordOld IS NULL)
BEGIN
SET #ReturnVal='1|Incorrect Username'
INSERT INTO FailedLogins(Username,Password,ClientType,Reason,IPAddress)
VALUES(#UserID,Hashbytes('SHA1',#Password),#Type,'Invalid Username',#IP)
END
ELSE
BEGIN
IF (#PasswordOld!=Hashbytes('SHA1',#Password))
BEGIN
SET #ReturnVal='1|Incorrect Password'
INSERT INTO FailedLogins(Username,Password,ClientType,Reason,IPAddress)
VALUES(#UserID,Hashbytes('SHA1',#Password),#Type,'Invalid Password',#IP)
END
ELSE
BEGIN
SET #ReturnVal='0|Logged in Successfully' +'|'+ rtrim(cast(#Type as char))
INSERT INTO SuccessfulLogins(Username,Password,ClientType,Reason,IPAddress)
VALUES(#UserID,Hashbytes('SHA1',#Password),#Type,'Valid Login Credentials Provided',#IP)
END
END
SELECT #ReturnVal
The problem here is that whenever I enter an Invalid Username,the stored procedure returns the correct message ie Incorrect Username but it stores NULL values in the fields ClientType and IPAddress in Failed Logins Table
Following is my insert query for Invalid username
IF (#PasswordOld!=Hashbytes('SHA1',#Password))
BEGIN
SET #ReturnVal='1|Incorrect Password'
INSERT INTO FailedLogins(Username,Password,ClientType,Reason,IPAddress)
VALUES(#UserID,Hashbytes('SHA1',#Password),#Type,'Invalid Password',#IP)
END
Can anyone help me to rectify this.How to check condition for username?
Thanks

Your code reads
SELECT #PasswordOld = Password,#Type=ClientType,#IP=IPAddress
FROM Clients
WHERE Username = #userid
Wouldn't this mean that no row will be returned for a Username that does not exist? So, the values for ClientType and IPAddress will not get populated and will remain NULL, which would be the expected functionality.
However, if you want to store some value, or these fields are not nullable, assign a static value to these parameters.

Your query is correct. When there is no match for the Username = #UserId , The #Type , #IP variables will be null. Since there is no record in the table for that UserName. What you can do is that in the declaration you can initiate to some default value,so that it will be inserted to table FailedLogins.
DECLARE #Type NVARCHAR(50)="DefaultType/NoType"
DECLARE #IP NVARCHAR(50)="0.0.0.1"
Something like the above.

If the username is invalid it does not appear in the table Clients so your fields pulled from that table will also be NULL. To negate this you could decide to use default values for ClientType and IPAddress using static values in your declarations, but storing this would just be obsolete data and I would think changing the structure of FailedLogins to not store this would seem more logical.

Related

SQL Server procedure for INSERT filtering

Is it possible to write a procedure in SQL Server that, before executing INSERT into a table, calls a function to check the format of email (1/0)?
INSERT will be executed only if the result of the checkemail function is 1, and in case of 0 it will return the error 'email is not valid'.
How it's done?
CheckEmail function:
CREATE FUNCTION dbo.CheckEmail
(#Email VARCHAR(100))
RETURNS BIT
AS
BEGIN
DECLARE #Result BIT
IF #Email IS NOT NULL
BEGIN
IF #Email LIKE '%["<>'']%'
OR #Email NOT LIKE '%#%.%'
OR #Email LIKE '%..%'
OR #Email LIKE '%#%#%'
OR #Email LIKE '%.#%'
OR #Email LIKE '%#.%'
OR #Email LIKE '%.cm'
OR #Email LIKE '%.co'
OR #Email LIKE '%.OR'
OR #Email LIKE '%.ne'
OR #Email LIKE '#%'
SET #Result = 0;
ELSE IF #Email LIKE '%_#__%.__%'
AND PATINDEX('%[^a-z,0-9,#,.,_,\-]%', #Email) = 0
SET #Result = 1;
END
RETURN #Result;
END
Users table:
CREATE TABLE Users
(
"Id" UNIQUEIDENTIFIER NOT NULL DEFAULT NEWID(),
"Email" VARCHAR(40) NOT NULL UNIQUE,
"Username" VARCHAR(30) NOT NULL,
"Password" VARCHAR(30) NOT NULL,
"Name" NVARCHAR(50) NOT NULL,
"Surname" NVARCHAR(50) NOT NULL
)
You can use IF statement like that :
IF CheckEmail('my#email.com')
INSERT INTO Users VALUES (...)
Also, you can add an ELSE statement if you want to do something with the line that doesn't correspond to what you want.
Documenation
There are several approaches, depending on your scenario, which you don't elaborate on. Assuming SQL Server given the SSMS tag.
If you are passing data to a stored procedure to handle a single insert, simply use if/then logic:
if dbo.CheckEmail(#email)=1
begin
/* Insert data here */
end
else
begin
/* raise any warnings / return error */
end
If you are inserting rows by selecting data from a source location, use a where criteria
insert into table Users (Email, Username, Password...)
select t1.Email, t1.Username, t1.Password...
from table t1
where dbo.CheckEmail(t1.email)=1
The most performant way would be to create a table-valued function instead of a scalar function which you can then use with cross apply
insert into table Users (Email, Username, Password...)
select t1.Email, t1.Username, t1.Password...
from table t1
cross apply dbo.CheckEmail(t1.email)ck
where ck.result=1
You are probably much better off doing this as a CHECK constraint
ALTER TABLE Users
ADD CONSTRAINT EmailCheck CHECK (
NOT( Email LIKE '%["<>'']%'
OR Email NOT LIKE '%#%.%'
OR Email LIKE '%..%'
OR Email LIKE '%#%#%'
OR Email LIKE '%.#%'
OR Email LIKE '%#.%'
OR Email LIKE '%.cm'
OR Email LIKE '%.co'
OR Email LIKE '%.OR'
OR Email LIKE '%.ne'
OR Email LIKE '#%'
) AND
Email LIKE '%_#__%.__%'
AND PATINDEX('%[^a-z,0-9,#,.,_,\-]%', Email) = 0
);

Compare two KeyValue types data in SQL Server 2012

I have the below data available in a table
DECLARE #AddressTbl As Table (ID int identity,Address varchar(100))
INSERT INTO #AddressTbl
VALUES ('State:AndhraPradesh,Dist:Prakasam')
Next time when I enter the same value I should be notified that this value exists in the table.
For this I will use an sp with warning message that the data is available. But I want how to implement the logic to compare the data.
Create Procedure usp_InsertAddress
(
#Address varchar(100)
)
AS
DECLARE #ID INT
SELECT #ID=(SELECT ID FROM #AddressTbl WHERE Address = #Address)
IF #ID IS NULL
BEGIN
INSERT INTO #AddressTbl
VALUES ('State:AndhraPradesh,Dist:Prakasam')
END;
I may enter the address like 'Dist:Prakasam,State:AndhraPradesh'
and there may be some blank spaces also. So need to parse the address and check the key and values.
I will use permanent table instead of table variable.
Appreciate your help.
You can use if exists for check. Or you can add unique CONSTRAINT in your table. The UNIQUE constraint ensures that all values in a column are different. This will return error if you are trying to insert duplicate value.
Create Procedure usp_InsertAddress
(
#Address varchar(100)
)
AS
if exists(SELECT ID FROM #AddressTbl WHERE Address = #Address)
begin
select 'Value is Already Exist in Table'---For Warning
end
else
BEGIN
INSERT INTO #AddressTbl
VALUES ('State:AndhraPradesh,Dist:Prakasam')
select 'Value Inserted Sucessful'---For Success
END;

Creating error record when SQL Server udf function returns a certain result

I have been wrecking my brain over this all weekend.
I have a SQL Server UDF to check whether a value passed as an argument will truncate.
CREATE FUNCTION willTruncate
(#fldValue nvarchar(200),
#fldSize smallint,
#fieldname nvarchar(40),
#tbl varchar(15))
RETURNS varchar(200)
AS
BEGIN
declare #Return varchar(200)
declare #fldLen smallint
SET #fldLen = len(#fldValue)
if #fldLen <= #fldSize
SET #Return = #fldValue
else
SET #Return = left(#fldValue,#fldSize-3) + '...'
RETURN #Return
END
The function works correctly to truncate the data the way I need it to when I use it in a SQL query like the sample below:
select top 10
'test' as db,
fname,
dbo.willTruncate(lname, 5, 'Last Name', 'People') as lastname,
dbo.willTruncate(address,40,'Address Line 1', 'People') as addressLine1
from
people
My problem is that I need to report back in some manner about the truncations so the end users can correct the record.
I have a table to populate and have tried to insert a record as part of the else clause, a separate function and a stored procedure. Each time I run the code it fails.
insert into tblTruncationErrors(trunkTable, trunkField, trunkValue)
values(#tbl, #fieldname, #fldValue)
or
CREATE FUNCTION dbo.logTruncation
(#fldValue nvarchar(200), #fieldname nvarchar(40), #tbl varchar(15))
RETURNS varchar(30)
AS
BEGIN
declare #Return int
insert into dbo.truncationErrors(trunkTable, trunkField, trunkValue)
Values (#tbl, #fieldname, #fldValue)
SET #Return = #fieldname
RETURN #Return
END
or
CREATE PROC sp_logTruncation
#tbl varchar(20),
#fldName varchar(30),
#fldValue varchar(200)
AS
SET NOCOUNT ON
insert into dbo.truncationErrors(trunkTable, trunkField, trunkValue)
Values (#tbl, #fldName, #fldValue)
SET NOCOUNT OFF
RETURN 1
GO
Running it as part of the original function code fails saying it needs to be done in a function or stored procedure. If I do it as a function it says I must use a stored procedure. Using it as a stored procedure results in a message saying it can only run from a function.
So, am I writing this wrong? Is there a way to do this. I am not insistent about it going into a table so a Excel or csv file output would be wonderful as well.

SQL Server: how to create a stored procedure

I'm learning sql from a book and I'm trying to write a stored procedure but I don't believe that I'm doing it correctly. Is the following way not valid in Microsoft SQL? If not, when is it valid, if ever?
create procedure dept_count(in dept_name varchar(20), out d_count integer)
begin
select count(*) into d_count
from instructor
where instructor.dept_name=dept_count.dept_name
end
I get the following error
Msg 156, Level 15, State 1, Procedure wine_change, Line 1
Incorrect syntax near the keyword 'in'.
T-SQL
/*
Stored Procedure GetstudentnameInOutputVariable is modified to collect the
email address of the student with the help of the Alert Keyword
*/
CREATE PROCEDURE GetstudentnameInOutputVariable
(
#studentid INT, --Input parameter , Studentid of the student
#studentname VARCHAR (200) OUT, -- Output parameter to collect the student name
#StudentEmail VARCHAR (200)OUT -- Output Parameter to collect the student email
)
AS
BEGIN
SELECT #studentname= Firstname+' '+Lastname,
#StudentEmail=email FROM tbl_Students WHERE studentid=#studentid
END
In T-SQL stored procedures for input parameters explicit 'in' keyword is not required and for output parameters an explicit 'Output' keyword is required. The query in question can be written as:
CREATE PROCEDURE dept_count
(
-- Add input and output parameters for the stored procedure here
#dept_name varchar(20), --Input parameter
#d_count int OUTPUT -- Output parameter declared with the help of OUTPUT/OUT keyword
)
AS
BEGIN
-- SET NOCOUNT ON added to prevent extra result sets from
-- interfering with SELECT statements.
SET NOCOUNT ON;
-- Statements for procedure here
SELECT #d_count = count(*)
from instructor
where instructor.dept_name=#dept_name
END
GO
and to execute above procedure we can write as:
Declare #dept_name varchar(20), -- Declaring the variable to collect the dept_name
#d_count int -- Declaring the variable to collect the d_count
SET #dept_name = 'Test'
Execute dept_count #dept_name,#d_count output
SELECT #d_count -- "Select" Statement is used to show the output
I think it can help you:
CREATE PROCEDURE DEPT_COUNT
(
#DEPT_NAME VARCHAR(20), -- Input parameter
#D_COUNT INT OUTPUT -- Output parameter
-- Remember parameters begin with "#"
)
AS -- You miss this word in your example
BEGIN
SELECT COUNT(*)
INTO #D_COUNT -- Into a Temp Table (prefix "#")
FROM INSTRUCTOR
WHERE INSTRUCTOR.DEPT_NAME = DEPT_COUNT.DEPT_NAME
END
Then, you can call the SP like this way, for example:
DECLARE #COUNTER INT
EXEC DEPT_COUNT 'DeptName', #COUNTER OUTPUT
SELECT #COUNTER
Try this:
create procedure dept_count(#dept_name varchar(20),#d_count int)
begin
set #d_count=(select count(*)
from instructor
where instructor.dept_name=dept_count.dept_name)
Select #d_count as count
end
Or
create procedure dept_count(#dept_name varchar(20))
begin
select count(*)
from instructor
where instructor.dept_name=dept_count.dept_name
end
CREATE PROCEDURE [dbo].[USP_StudentInformation]
#S_Name VARCHAR(50)
,#S_Address VARCHAR(500)
AS
BEGIN
SET NOCOUNT ON;
DECLARE #Date VARCHAR(50)
SET #Date = GETDATE()
IF EXISTS (
SELECT *
FROM TB_StdFunction
WHERE S_Name = #S_Name
AND S_Address = #S_Address
)
BEGIN
UPDATE TB_StdFunction
SET S_Name = #S_Name
,S_Address = #S_Address
,ModifiedDate = #Date
WHERE S_Name = #S_Name
AND S_Address = #S_Address
SELECT *
FROM TB_StdFunction
END
ELSE
BEGIN
INSERT INTO TB_StdFunction (
S_Name
,S_Address
,CreatedDate
)
VALUES (
#S_Name
,#S_Address
,#date
)
SELECT *
FROM TB_StdFunction
END
END
Table Name : TB_StdFunction
S_No INT PRIMARY KEY AUTO_INCREMENT
S_Name nvarchar(50)
S_Address nvarchar(500)
CreatedDate nvarchar(50)
ModifiedDate nvarchar(50)
Create this way.
Create procedure dept_count(dept_name varchar(20),d_count integer)
begin
select count(*) into d_count
from instructor
where instructor.dept_name=dept_count.dept_name
end
try this:
create procedure dept_count( #dept_name varchar(20), #d_count INTEGER out)
AS
begin
select count(*) into d_count
from instructor
where instructor.dept_name=dept_count.dept_name
end
To Create SQL server Store procedure in SQL server management studio
Expand your database
Expand programmatically
Right-click on Stored-procedure and Select "new Stored Procedure"
Now, Write your Store procedure, for example, it can be something like below
USE DatabaseName;
GO
CREATE PROCEDURE ProcedureName
#LastName nvarchar(50),
#FirstName nvarchar(50)
AS
SET NOCOUNT ON;
//Your SQL query here, like
Select FirstName, LastName, Department
FROM HumanResources.vEmployeeDepartmentHistory
WHERE FirstName = #FirstName AND LastName = #LastName
GO
Where, DatabaseName = name of your database
ProcedureName = name of SP
InputValue = your input parameter value (#LastName and #FirstName) and type = parameter type example nvarchar(50) etc.
Source: Stored procedure in sql server (With Example)
To Execute the above stored procedure you can use sample query as below
EXECUTE ProcedureName #FirstName = N'Pilar', #LastName = N'Ackerman';

SQL Insert Procedure

Why isn't my insert procedure returning the ID of the newly inserted row? AND, when calling this procedure, why do I have to supply a value for #EventId? That column is a PK with IDENTITY.
IF OBJECT_ID ( 'vjsql.EventsINSERT', 'P') IS NOT NULL
DROP PROCEDURE EventsINSERT
GO
CREATE PROCEDURE EventsINSERT
#EventId int OUTPUT,
#EventDate datetime,
#Title varchar(100),
#IsActive bit
AS
BEGIN
INSERT INTO EventCalendar ( EventDate, Title, IsActive)
VALUES ( #EventDate, #Title, #IsActive)
SELECT #EventId = SCOPE_IDENTITY()
END
How are you making a call to the stored procedure?
This SP is returning the value of EventID by means of using OUTPUT parameters.
i.e. In programming terms, this is a procedure (not a function) that accepts an OUTPUT parameter which will be set with the value during the execution of the stored procedure.
For this, you will have to pass the variable for #EventID. The value of which will be set within the procedure and you will be able to read the value of it, once the procedure has finished.
See the example code below.
DECLARE #NewEventID INT
EXEC EventsINSERT
#EventId = #NewEventID OUTPUT,
#EventDate = '08/04/09',
#Title = 'Hello World',
#IsActive = 0
SELECT #NewEventID
Try adding some statement terminators:
BEGIN
INSERT INTO EventCalendar ( EventDate, Title, IsActive)
VALUES ( #EventDate, #Title, #IsActive);
SELECT #EventId = SCOPE_IDENTITY();
END
AND, when calling this procedure, why do I have to supply a value for #EventId? That column is a PK with IDENTITY.
You don't, but you do need to supply a variable of type int (or compatible with int) for the output value to be put into.
You don't need to specify a value for the OUTPUT parameter, you need to specify which local variable the output gets put into:
By default, SQL Management Studio names the parameter and the variable the same, which can be confusing. Here's an example of your SP being called:
DECLARE #InsertedEventId int
EXEC [dbo].[EventsINSERT]
#EventId = #InsertedEventId OUTPUT,
#EventDate = N'2009-08-05',
#Title = N'Some event',
#IsActive = 1
-- Display ID as result set
SELECT #InsertedEventId
Just to clarify: your stored procedure is fine. I used it as-is.
Why isn't my insert procedure
returning the ID of the newly inserted
row?
Your code should work. Try in the console instead of
SELECT #EventId = SCOPE_IDENTITY()
doing
SELECT SCOPE_IDENTITY()
and view what happens. Is possible that you are calling it the wrong way. You should store the value of the OUTPUT variable in a variable in the scope where you call this SP.
when calling this procedure, why do I
have to supply a value for #EventId?
Because you have to supply a value for every parameter you have. It doesn't matter if is a real value, it will be discarded, but you must call the stored procedure with a variable in this parameter to catch the returned value.
I'm pretty rusty with tsql, but don't you need to explicitly select ##identity to get that row id? That's where i'd go digging as I think scope_identity() may not return a value in the context of a user function/procedure.

Resources