How can I implement MS SQL 2014 Stored Procedure - sql-server

I am new to MS SQL 2014 stored procedure. I have a table as shown below. I want to create a stored procedure.
I design my stored procedure but I feel so difficult that I can’t even start. Can anyone help me how can I do that?
I have to send CardNo, CardPassword and the PosSerialNo to SQL store procedure. In return I need to get customer name, surname and the amount.
SENDING: CardNo, CardPass, PosSerialNo
RECEVING:
If Sending.CardPass = CardPasswordTable.Password
Do the following:
If successful I get: CustomerName, CustomerSurname and Amount
If not I get: “No Data Found”
MY TABLES:
1) CardIssueTable:
Columns:
CardId, CardNo, CustId
2) CustomerTable:
Columns:
CustId, CustName, CustSurname
3) PosTable:
Columns:
PosId, PosSerial, PosLocation
4) PaymentTable:
Columns:
PaymentId, PaymentLoaction, PaymentAmount
5) CardPasswordTable:
Columns:
PassId, Password
Edited:
Here is my Stored Procedure. When I execute I get an error.
Store Procedure:
USE [LTKB_Card]
GO
/****** Object: StoredProcedure [dbo].[CardCustomerControl] Script Date: 2.03.2016 10:03:15 ******/
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
/*parameters*/
ALTER Procedure [dbo].[CardCustomerControl](
#CardNo varchar(50),
#CardPass varchar(10),
#PosSerialNo varchar(50)
)
AS
BEGIN
DECLARE /*internal of sp*/
#CustName varchar(100),
#CustId int,
#CustSurName varchar(100),
#Amout int,
#PosId int,
#PassId int
SELECT #CustName=CUS.CustomerName, #CustSurName=CUS.CustomerSurname ,#CustId=C.CardCustomer
FROM CardBASIM C
INNER JOIN CUSTOMERS CUS ON C.CardCustomer=CUS.CustomerName
WHERE C.CardNo=#cardNo
SELECT #PassId=PASID FROM CardPASSLIST C WHERE C.CardPassowrd=#CardPass
SELECT #Amout=PT.PaymentAmount
FROM POS P
INNER JOIN PAYMENT PT on P.PosLocation=PT.PAYID
WHERE P.PosSerial=#PosSerialNo
if (#CustId is not null and #PassId is not null and #PosId is not null)
begin
select #CustName CustName, #CustSurName CustSurname , #Amout Amount
end
else
begin
select 'NoDataFound'
end
END
Execute Statement:
USE [LTKB_Card]
GO
DECLARE #return_value int
EXEC #return_value = [dbo].[CardCustomerControl]
#CardNo = N'5852354822730001',
#CardPass = N'jSCm6xkBpK',
#PosSerialNo = N'RR-312-001387'
SELECT 'Return Value' = #return_value
GO
Error:
Msg 248, Level 16, State 1, Procedure ElitcardCustomerControl, Line 21
The conversion of the varchar value '5852354822730001' overflowed an
int column.
(1 row(s) affected)
(1 row(s) affected)
And here are the relationship of the tables:

Looking at the data model this line
INNER JOIN CUSTOMERS CUS ON C.CardCustomer=CUS.CustomerName
Is joining a string to an integer. I can't look at the data to see if this is the exact problem but according to your model the join you want is this:
INNER JOIN CUSTOMERS CUS ON C.CardCustomer=CUS.CUSTID
This is a standard relationship -- I've no idea why you felt the Customer's name was the field to join to.

I truly hope you do not store password in plain text, and I don't get all relations between your tables (for example where is relation between postable and paymenttable, between passwordtable and cartable), but I give you an example of SP you needed. Don't forget IT'S JUST EXAMPLE.
CREATE PROCEDURE dbo.spnamegoeshere
#CardNo int,
#CardPass nvarchar(8),
#PosSerialNo nvarchar(8)
AS
BEGIN
--Check if password is Sending.CardPass = CardPasswordTable.Password
IF (SELECT ISNULL(PassId,0) FROM CardPasswordTable WHERE Password = #CardPass) != 0
BEGIN
-- If successful you get: CustomerName,
-- CustomerSurname and Amount
-- not sure of table relations
SELECT ct.CustomerName, ct.CustomerSurname, pat.PaymentAmount
FROM CardIssueTable cit
INNER JOIN CustomerTable ct ON cit.CustId = Ct.CustId
LEFT JOIN PosTable pt ON pt.PosSerial = #PosSerialNo
LEFT JOIN PaymentTable pat ON pt.PosLocation = pat.PaymentLoaction
WHERE CardNo = #CardNo
END
ELSE
BEGIN
--If not you get: “No Data Found”
SELECT 'No Data Found'
END
END

Related

Invalid Object Name for Temp Table in Stored Procedure

I'm trying to use a temp table to update a database table in a stored procedure.
My client was throwing an error about an illegal null value, so I tried testing within SSMS and it told me that the name of the temp table was invalid (regardless of what I named it).
If I run the beginning and change the INSERT INTO SERVICE SELECT S.* to simply SELECT S.* and run the code after Declaring and Defining #OldServicesString (so I can leave out the ALTER/CREATE PROCEDURE line) it runs exactly as expected.
Here's the beginning of the SP:
ALTER PROCEDURE [dbo].[app_CreateNewServicesOldFSD] (#OldServicesStr nvarchar(max)) AS
SET NOCOUNT ON
DECLARE #User char(10) = (SELECT TOP 1 CREATED_BY_USER FROM BATCHLOG WHERE BPROCESS_ID = 3 ORDER BY ID DESC);
DECLARE #LastOldService int = (SELECT MAX(ID) FROM SERVICE);
SELECT TOP 0 * INTO #Service FROM SERVICE;
ALTER TABLE #Service
DROP COLUMN RECNUM;
INSERT INTO #Service exec dbo.app_NewServicesOldFSD
;WITH cteOldFSDsToCreate AS (
SELECT JobID.Item JobID, CONVERT(date,ServDate.Item,103) ServDate
FROM dbo.SplitStringToTable(#OldServicesStr,',',2) JobID
INNER JOIN dbo.SplitStringToTable(#OldServicesStr,',',2) ServDate ON JobID.Rw = ServDate.Rw AND JobID.Cl = 0 AND ServDate.Cl = 1
)
INSERT INTO SERVICE SELECT S.*
FROM #Service S
INNER JOIN cteOldFSDsToCreate N ON N.JobID = S.JOB_ID AND N.ServDate = S.DATE
DROP TABLE #Service
A useable and likely #OldServicesStr could be '11428,23/07/2019,11429,23/07/2019,15186,5/10/2019'
To test it in SSMS I opened a new Query and typed in
exec app_CreateNewServicesOldFSD '11428,23/07/2019,11429,23/07/2019,15186,5/10/2019'
And got the following error:
Warning: Null value is eliminated by an aggregate or other SET operation.
Msg 208, Level 16, State 0, Procedure app_CreateNewServicesOldFSD, Line 65 [Batch Start Line 7]
Invalid object name '#Service'.
Completion time: 2020-11-20T20:36:57.1356921+11:00
I know that is not Your case but in the sake of not forget, there is also a limitation using Biztalk WCF-Custom adapter with SQL Bindings and temp tables.
According to this site :
http://thoughtsofmarcus.blogspot.com/2010/11/calling-stored-procedures-from-biztalk.html
You need to SET FMTONLY OFF before creating temp tables and inserting into them and
SET FMTONLY ON before selecting from them as in example from below.
ALTER PROCEDURE [dbo].[FetchTestData]
(#a4 varchar(4))
AS
DECLARE #FmtOnlyIsSet bit = 0
IF (1=0) BEGIN SET #FmtOnlyIsSet = 1 END
IF #FmtOnlyIsSet = 1
SET FMTONLY OFF
SELECT t1, t2, t3 INTO #temp01 FROM Table_1
IF #FmtOnlyIsSet IS NULL
SET FMTONLY ON
SELECT t1, t2, t3 FROM #temp01
RETURN

SQL Server trigger on a procedure failing

I am trying to trigger a stored procedure to take the inserted values into my stored procedure as parameters and it is not letting me.
My table flow goes like this: a patient's history information will be inserted (HISTORY_APPOINTMENTS) and if at the time the patient has a column value of HasSuicidalThoughts = 'Y' I want the trigger to send the inserted patients information into a table I created called SuicideWatchLog.
First I created the table:
/* Table Creation for SuicideWatch Log*/
CREATE TABLE SuicideWatchLog
(
logNum integer IDENTITY(1,1) NOT NULL PRIMARY KEY,
PatientStudy# integer FOREIGN KEY References Patients(PatientStudy#),
PatientName varchar(20),
[Date] date,
Dr# integer FOREIGN KEY References DOCTORS(Dr#),
DaysinStudy integer
)
Next I created the procedure:
CREATE PROCEDURE AddSuicideWatch
#PatientStudy# integer,
#PatientName varchar(20),
#Date date,
#Dr# integer,
#DaysinStudy integer
AS
BEGIN
INSERT INTO SuicideWatchLog(PatientStudy#, Date, Dr#)
(SELECT PatientStudy#, ApptDate, Dr#
FROM APPOINTMENTS
WHERE #PatientStudy# = PatientStudy#
AND #Date = ApptDate
AND #Dr# = Dr#)
INSERT INTO SuicideWatchLog(PatientName, DaysinStudy)
(SELECT PatientFName, datediff(day,StudyStartDate,getdate())
FROM PATIENTS
WHERE #PatientName = PatientFName
AND #DaysinStudy = datediff(day,StudyStartDate,getdate()))
END
Finally I created the trigger:
CREATE TRIGGER SuicidalPatient
ON HISTORY_APPOINTMENT
AFTER INSERT
AS
EXEC AddSuicideWatch(
SELECT (I.PatientStudy#, P.PatientFName, A.ApptDate,
FROM INSERTED I
JOIN APPOINTMENTS A ON I.Appt# = A.Appt#
JOIN PATIENTS P ON I.PatientStudy# = P.PatientStudy#)
I expected this to allow me to send the inserted values into the stored procedure to trigger the creation of the log, but instead I am getting an error that is telling me my parameters aren't being found.
Is this an issue with the select statement, or is it a problem with the procedure itself?
Is this an issue with the select statement, or is it a problem with the procedure itself?
Your stored procedure accepts scalar parameters. You can't pass a whole resultset to it. You can:
1) Integrate the INSERTs directly into the trigger body, eliminating the stored procedure.
2) Open a cursor over the query in the trigger, and loop through the rows, calling the stored procedure fore each one.
3) Declare a User-Defined Table Type matching the query result rows, declare and load an instance of the table type in the trigger body, and change the stored procedure to accept a Table-Valued Parameter.
you cant pass table to sp , but i know 2 ways for that :
1- use user defined type like that :
create type NewTable AS table (PatientStudy# int, PatientFName nvarchar(max), ApptDate date)
and the insert into NewTable Then call sp
declare #TempTable NewTable
insert into #TempTable(PatientStudy# , PatientFName , ApptDate)
select I.PatientStudy#, P.PatientFName, A.ApptDate,
FROM INSERTED I
JOIN APPOINTMENTS A ON I.Appt# = A.Appt#
JOIN PATIENTS P ON I.PatientStudy# = P.PatientStudy#
EXEC AddSuicideWatch( #TempTable)
and of course you should edit your SP :
CREATE PROCEDURE AddSuicideWatch
#Table NewTable
AS
BEGIN
INSERT INTO SuicideWatchLog(PatientStudy#, Date, Dr#)
SELECT PatientStudy#, ApptDate, Dr#
FROM APPOINTMENTS A join #Table T ON
A.PatientStudy# = T.PatientStudy#
A.Date = T.ApptDate
A.Dr# = D.Dr#
INSERT INTO SuicideWatchLog(PatientName, DaysinStudy)
(SELECT PatientFName, datediff(day,StudyStartDate,getdate())
FROM PATIENTS P join #Table T ON
T.PatientName = P.PatientFName
AND A.DaysinStudy = datediff(day,StudyStartDate,getdate()))
END
And the seccond way : just pass the primary key to sp and handle other things in sp

Get data using same parameter with different values in sql

I need to show multiple record tables using same parameter suppose some ID.
Data has been differ as per that parameter values which is different for all.
I could not understand your requirement. But you can query sys.columns for column names to find the tables which have the same column
select
OBJECT_NAME(object_id) as table_name,
name as column_name
from sys.columns
where
name like N'%id%'
For passsing a list of IDs into a stored procedure, most recent method is using Table Valued Parameters aka TVP
Following is an example for using TVP in SQL Server
First you need to create the type in database. Then you populate the variable of the table type with data. You have to do these in the front end. Then you pass this parameter to your stored procedure
I used databases view for sample, you can use your table and ID column instead
create type IDTableType as table
(
Id int
);
go
create procedure ReadData (
#IdList IDTableType readonly
)
as
select *
from sys.databases as d
inner join #IdList as p
on d.database_id = p.id
go
declare #IDs as IDTableType
insert into #IDs values (1),(5),(3)
exec ReadData #IDs
But maybe the most common usage is with string parameter which is concatenated form of IDs
This time you need a SQL split string function to split input parameter into ID list. You can use the referred sample or use one of the custom split functions on the web. If you are using SQL Server 2016 or later, you can use string_split function, too
create procedure ReadData2 (
#IdList varchar(max)
)
as
select *
from sys.databases as d
inner join dbo.split(#IdList,0,0) as s
on d.database_id = s.val
go
declare #IDs as varchar(max) = '1,3,5,6'
exec ReadData2 #IDs
First thing i make fun in sql:
USE [ZAB_HCTMS]
GO
/****** Object: UserDefinedFunction [dbo].[LCNos] Script Date: 1/8/2019 1:09:54 PM ******/
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
/****** Object: UserDefinedTableType [dbo].[oldTVP_ConsignmentNoteLineItems] Script Date: 1/7/2019 1:00:53 PM ******/
ALTER FUNCTION [dbo].[LCNos]
(
#LCNo NVARCHAR(MAX),
#Comma CHAR(1)
)
RETURNS #Output TABLE (
ID NVARCHAR(1000)
)
AS
BEGIN
DECLARE #StartIndex INT, #EndIndex INT
SET #StartIndex = 1
IF SUBSTRING(#LCNo, LEN(#LCNo) - 1, LEN(#LCNo)) <> #Comma
BEGIN
SET #LCNo = #LCNo + #Comma
END
WHILE CHARINDEX(#Comma, #LCNo) > 0
BEGIN
SET #EndIndex = CHARINDEX(#Comma, #LCNo)
INSERT INTO #Output(ID)
SELECT SUBSTRING(#LCNo, #StartIndex, #EndIndex - 1)
SET #LCNo = SUBSTRING(#LCNo, #EndIndex + 1, LEN(#LCNo))
END
RETURN
END
then sp for this:
-- EXEC GetLCsDetails '2188,2196,2201'
alter PROCEDURE GetLCsDetails
#LCNos VARCHAR(100)
AS
BEGIN
SELECT lr.*, lr.PayBalance 'TotalPayBalance', s.Name 'SuppName',
cb.AdvancePayment, s.[Address] 'Address',
s.PinCode, pod.SupplierBillNo
FROM LorryChallans lr
left join ConsignmentBookings cb on lr.ConsignmentBookingID =
cb.ConsignmentBookingID
left join Suppliers s on cb.VehicleSupplierID = s.SupplierID
left join POD pod on lr.ConsignmentBookingID = pod.ConsignmentBookingID
WHERE
lr.LorryChallanNumber
IN( SELECT CAST(ID AS INTEGER) FROM dbo.LCNos(#LCNos, ',') )
END
and finally passing string comma separated ids from jquery:
function chk()
{
$('.Checkbox:checked').map(function () {
return $(this).attr('data-lcno');
}).get().join(',')
}
data-lcno is data attribute to checkboxlist.

How to avoid duplicate records using stored procedure [duplicate]

This question already has answers here:
SQL Server Insert if not exists
(13 answers)
Closed 3 years ago.
I want to write a stored procedure to insert data into a table and also to check whether same data already exist?
If yes, then exception throw as already exist. But I don't know where should I add an exception. Please help.
ALTER PROCEDURE [dbo].[datakutipantest1]
AS
BEGIN
DECLARE #ModifiedDate datetime = GETDATE()
INSERT INTO spk_DataKutipan ([NO_BIL], [NO_AKAUN], [TKH_BAYAR],
[STESYEN], [AMAUN_BAYAR], [JENIS_BAYAR], [NO_RESIT], [STATUS], [NO_VOT], [TKH_MODIFIKASI])
SELECT
D.BillNo,
D.AccountNo,
D.TxDate,
D.ReferenceCode,
D.Amount,
PaymentTypeId,
D.ReferenceNo,
D.Status,
D.RevenueCode,
#ModifiedDate
FROM
(SELECT
B.ComponentId,
B.AccountNo,
B.BillNo,
B.RevenueCode,
B.Amount,
B.TxId,
ReferenceNo,
B.ReferenceCode,
status,
TxDate
FROM
(SELECT
A.ComponentId,
A.TxId,
AccountNo,
BillNo,
RevenueCode,
Amount,
C.ReferenceCode
FROM
rcs_TxBillItem A
INNER JOIN
(SELECT
ComponentId,
ComponentName,
ReferenceCode
FROM
rcs_Component
WHERE
IsDeleted = 0) C ON C.ComponentId = A.ComponentId) B
INNER JOIN
rcs_TxBill P ON P.TxId = B.TxId) D
INNER JOIN
rcs_TxBillPayment E ON E.TxId = D.TxId
END
GO
CREATE PROCEDURE [dbo].[Useradd]
#username varchar(20),
#pword nvarchar(20),
#empname varchar(20),
#email nvarchar(50),
#designation varchar(20),
#reportto varchar(20) AS
IF (SELECT COUNT(*) FROM Users WHERE username= #username) < 1
BEGIN
INSERT INTO Users(username,pword,empname,email,designation,reportto)
VALUES(#username,#pword,#empname,#email,#designation,#reportto)
END
Consider to use MERGE
MERGE <target_table> [AS TARGET]
USING <table_source> [AS SOURCE]
ON <search_condition> --For example ColumnSource = ColumnTable
WHEN MATCHED --Rows already exist
THEN UPDATE target_table SET ... --Do Update for example
WHEN NOT MATCHED BY TARGET --Rows not exist on Target Table
THEN INSERT(...) VALUES(...) --Do Insert for example
WHEN NOT MATCHED BY SOURCE --Rows not exist on Source table but exists on Target Table
THEN DELETE ... --Do Delete for example
The MERGE statement basically merges data from a source result set to a target table based on a condition that you specify and if the data from the source already exists in the target or not. The new SQL command combines the sequence of conditional INSERT, UPDATE and DELETE commands in a single atomic statement, depending on the existence of a record.

Already an object named in the database issue

I am trying to execute an email that contains the results of a stored procedure. I was looking at other posts in stackoverflow but cannot seem to get past an error that states "Msg 2714, Level 16, State 1, Procedure CompareConfirm_FraudRules, Line 38
There is already an object named '##returnInactiveRules' in the database." I've looked in the DB and there is no object that exists with this name already. Any suggestions on how to fix this issue would be appreciated. Thanks.
Here is the my SP:
BEGIN
CREATE TABLE ##returnInactiveRules (
ProductName varchar(100),
ChannelName varchar(100),
StrategyCode varchar(100),
StrategyName varchar(100),
RuleCode varchar(100),
RuleName varchar(100),
On_Off varchar(5)
);
-- SET NOCOUNT ON added to prevent extra result sets from
-- interfering with SELECT statements.
SET NOCOUNT ON;
-- Insert statements for procedure here
-- SELECT R.RuleCode, R.Name as RuleName, S.StrategyCode, S.Name as StrategyName, R.IsActive
SELECT DISTINCT
CASE
WHEN PC.ProductIdentifier='2000' THEN 'GP'
WHEN PC.ProductIdentifier='1000' THEN 'MB'
END as ProductName, C.Name as ChannelName, S.StrategyCode, S.Name as StrategyName, R.RuleCode, R.Name as RuleName,
CASE
WHEN R.IsActive = 1 THEN 'On'
WHEN R.IsActive = 0 THEN 'Off'
END as On_Off
INTO ##returnInactiveRules
FROM dbo.[Rule] R
INNER JOIN dbo.Strategy S
on S.KnockoutRuleSet = R.KnockoutRuleSet
INNER JOIN dbo.RFAI P
on R.RFAIId = P.RFAIId
INNER JOIN dbo.DecisionStatus D
on D. StatusId = R. StatusId
LEFT OUTER JOIN dbo.NOAA N
on N.NOAAId = R.NOAAId
INNER JOIN dbo.RuleQuestionsXRef Q
ON Q.RuleId = R.RuleId
INNER JOIN ProductChannelStrategyRuleXref X
ON X.RuleId = R.RuleId
INNER JOIN ProductChannelStrategy CS
ON CS.ProductChannelStrategyId = X.ProductChannelStrategyId
INNER JOIN ProductChannel PC
ON PC.ProductChannelId = CS.ProductChannelId
INNER JOIN dbo.Channel C
ON C.ChannelId = PC.ChannelId
WHERE R.IsActive = 0
AND R.RuleCode IN ('F06',
'F07',
'F11',
'F12',
'F14',
'F15',
'F16',
'F17',
'F19',
'F23',
'F25',
'F26',
'F10'
)
-- ORDER BY R.RuleCode, R.Name;
ORDER BY ProductName, C.Name, S.StrategyCode, S.Name, R.RuleCode, R.Name;
-- SELECT * FROM #returnValue;
-- Email the results in the #returnValue table --
EXEC msdb.dbo.sp_send_dbmail
#execute_query_database='Prod-XXX',
#recipients=N'msavoy#xxx.com',
#body='Attached please find a file with the results.',
#subject ='Compare Fraud Rule Results',
#profile_name ='Reports',
#query ='EXEC CompareConfirm_Rules',
#attach_query_result_as_file = 1,
#query_attachment_filename ='CompareRuleResults.txt'
END
DROP TABLE ##returnInactiveRules;
GO
If exists Drop it, then create the table
IF Object_id('tempdb..##returnInactiveRules') IS NOT NULL
DROP TABLE ##returnInactiveRules
CREATE TABLE ##returnInactiveRules
(
ProductName VARCHAR(100),
ChannelName VARCHAR(100),
StrategyCode VARCHAR(100),
StrategyName VARCHAR(100),
RuleCode VARCHAR(100),
RuleName VARCHAR(100),
On_Off VARCHAR(5)
);
Temp tables which start with ## are global temp tables, so if you have 2 connection opened, and one of them created a table called ##Temp, you would not be able to create the same table from connection 2, until it is dropped by any of the 2 connections.
Best thing would be to use #returnInactiveRules and check for existence before creating it.
IF OBJECT_ID('tempdb..#returnInactiveRules') IS NOT NULL
DROP TABLE #returnInactiveRules
GO
Have the drop statement at the beginning and if it's a global temp table ensure that only one process is creating it at any one time as two cannot exist simultaneously..
Also, unless you require other sessions to access the data, consider using a temp table rather than a global temp table by replacing the ## with #

Resources