Convert this inline SQL to stored procedure - c#

How can I convert this inline SQL to a stored procedure
SELECT
PM.ProjectName
,[PurposeorReason]
,Reg.Name
,EA.Comment as Comment
,[FromDate]
,[VoucherID]
,[TotalAmount]
,ex.CreatedOn
FROM [TimesheetDB].[dbo].[Expense] ex
inner join Registration Reg on reg.RegistrationID = ex.UserID
inner join ProjectMaster PM on ex.ProjectID =PM.ProjectID
inner join AssignedRoles AR on reg.RegistrationID = AR.RegistrationID
inner join ExpenseAuditTB EA on ex.ExpenseID = EA.ExpenseID
where FromDate between '2019-09-25' and '2019-09-29'
and ea.ProjectID IN (1,2,5)
and EA.Status = 2
I have issues with the (1,2,5) part. I have it in C# as a string "1,2,5" and the ProjectID is integer.
I know I am doing something wrong. The query itself works well.

I suggest a table-valued parameter to pass lists/arrays to a stored procedure. In the C# code, specify parameter type SqlDbType.Structured as the parameter type. The parameter value can be a DataTable, IEnumerable<SqlDataRecord>, or DbDataReader. I suggest a DataTable with a single column for this use case.
CREATE TYPE dbo.TVPProjectIdList AS TABLE (
ProjectId int NOT NULL PRIMARY KEY
);
GO
CREATE PROCEDURE dbo.Example
#StartDate date
, #EndDate date
, #Status int
, #ProjectIdList dbo.TVPProjectIdList READONLY
AS
SET NOCOUNT ON;
SELECT
PM.ProjectName
,[PurposeorReason]
,Reg.Name
,EA.Comment as Comment
,[FromDate]
,[VoucherID]
,[TotalAmount]
,ex.CreatedOn
FROM [TimesheetDB].[dbo].[Expense] ex
inner join Registration Reg on reg.RegistrationID = ex.UserID
inner join ProjectMaster PM on ex.ProjectID =PM.ProjectID
inner join AssignedRoles AR on reg.RegistrationID = AR.RegistrationID
inner join ExpenseAuditTB EA on ex.ExpenseID = EA.ExpenseID
where FromDate between #StartDate and #EndDate
and ea.ProjectID IN (SELECT ProjectId FROM #ProjectIdList)
and EA.Status = #Status;
GO

You have to add commas at the beginning and at the end of #ProjectId string.
In c# How to Get comma value at the beginning and at the end
string str = "1,2,5";
string replaced=str.Replace(',',',');
string concatenatdvalue=","+replaced+',';
Result = ",1,2,5,"
Then result value you can Pass as #ProjectId into SQL Server......
CREATE PROCEDURE dbo.sp_ProjectReport
(
#FromDate VARCHAR(20)=NULL,
#ToDate VARCHAR(20)=NULL,
#ProjectId VARCHAR(50)=NULL,
#StatusId INT=NULL
)
AS
BEGIN
SELECT
PM.ProjectName
,[PurposeorReason]
,Reg.Name
,EA.Comment as Comment
,[FromDate]
,[VoucherID]
,[TotalAmount]
,ex.CreatedOn
FROM [TimesheetDB].[dbo].[Expense] ex
inner join Registration Reg on reg.RegistrationID = ex.UserID
inner join ProjectMaster PM on ex.ProjectID =PM.ProjectID
inner join AssignedRoles AR on reg.RegistrationID = AR.RegistrationID
inner join ExpenseAuditTB EA on ex.ExpenseID = EA.ExpenseID
where
convert(DATETIME,FromDate) BETWEEN Convert(DATETIME,CASE WHEN isnull(#FromDate,'')='' THEN FromDate ELSE isnull(#FromDate,'') END)
AND Convert(DATETIME, CASE WHEN isnull(#ToDate,'')='' THEN FromDate ELSE isnull(#ToDate,'') END)
and CHARINDEX(','+cast(ea.ProjectID as varchar(100))+',', #ProjectId) > 0
and EA.Status = #StatusId
END
Testing Script For Executing SP
EXEC dbo.sp_ProjectReport
#FromDate='2019-09-25',
#ToDate='2019-09-29',
#ProjectId=',1,2,5,',
#StatusId='2'
Note:- Here i'm changing also logic of FromDate to ToDate
.........null part is also Handle in Custom Date Range.......
For E.g.
If you are enter only FromDate as "07/06/2017" then it will give you
from result("07/06/2017" to last Date)

Related

Passing formatted string and actual parameters to stored procedure from C#

I execute a stored procedure as follows:
exec SALESREPORTFORWEB
#StartDate = '03/20/2017', #EndDate = '03/21/2017'
Stored Procedure
CREATE proc [dbo].[SALESREPORTFORWEB]
--SALESREPORTFORWEB #StartDate='03-20-2017' ,#EndDate='03-28-2017',#usercode in ('2739','1609')
#StartDate DATETIME =NULL ,
#EndDate DATETIME =NULL ,
#ITEMCODE VARCHAR(100)=NULL,
#ITEMDESCRIPTION VARCHAR(100)=NULL,
#CLIENTCODE Varchar(25) = null,
#CLIENTNAME VARCHAR(100)=NULL,
#CLIENTBRANCHCODE VARCHAR(100)=NULL,
#CLIENTBRANCHNAME VARCHAR(100)=NULL,
#BRANDCODE VARCHAR (25)=NULL,
#BRANDNAME VARCHAR(100)=NULL,
#USERCODE VARCHAR(25)=NULL,
#USERNAME VARCHAR(100)=NULL,
#SUBCHANNEL VARCHAR(25)=NULL
AS
SELECT H.UserCode,U.SALESMANNAME, CONVERT(CHAR(10), H.TrxDate, 103) AS DATE,D.ItemCode,I.Description AS ITEMDESCRIPTION,d.ItemGroupLevel5 AS BRANDCODE,
B.Description AS BRANDNAME,
H.ClientCode,
C1.Description AS Client,H.ClientBranchCode,C2.Description, C2.SubChannelCode AS BRANCHSUBCHANNEL,
ROUND(
SUM(
CASE WHEN D.QuantityLevel1 > 0 THEN
D.QuantityLevel1 * PriceUsedLevel1
ELSE
D.QuantityLevel3 * PriceUsedLevel3
END - ISNULL(D.TotalDiscountAmount, 0)
), 2) AS TrxAmount,SUM(D.QuantityBU) AS QTY
FROM tblTrxHeader H INNER JOIN
tblTrxDetail D ON H.TrxCode = D.TrxCode AND D.TrxStatus > 0 INNER JOIN
tblBrand B ON B.Code=D.ITEMGROUPLEVEL5 INNER JOIN
tblClient C1 ON H.ClientCode = C1.Code
INNER JOIN tblClient C2 ON H.ClientBranchCode=C2.Code
INNER JOIN TBLITEM I ON I.ITEMCODE=D.ITEMCODE
/*LEFT OUTER JOIN
tblRegion R ON R.Code = C.RegionCode*/ LEFT OUTER JOIN
vw_UnitManagers U ON U.SalesmanCode = H.UserCode
WHERE
H.TrxType IN (1) AND
DATEDIFF(dd,H.TrxDate,ISNULL(#StartDate,GETDATE())) <= 0 AND DATEDIFF(dd,H.TrxDate,ISNULL(#EndDate,GETDATE())) >= 0 AND
D.ITEMCODE= ISNULL(#ITEMCODE,D.ITEMCODE) AND
H.CLIENTCODE= ISNULL(#CLIENTCODE,H.CLIENTCODE)AND
H.ClientBranchCode=ISNULL(#CLIENTBRANCHCODE,H.ClientBranchCode) AND
D.ItemGroupLevel5=ISNULL(#BRANDCODE,D.ItemGroupLevel5)AND
H.UserCode in (ISNULL(#USERCODE,H.UserCode)) AND
C2.SubChannelCode=ISNULL(#SUBCHANNEL,C2.SubChannelCode)AND
B.Description LIKE('%'+ISNULL(#BRANDNAME,B.Description)+'%')AND
I.Description LIKE('%'+ISNULL(#ITEMDESCRIPTION,I.Description)+'%')AND
C1.Description LIKE('%'+ISNULL(#CLIENTNAME,C1.Description)+'%')AND
C2.Description LIKE('%'+ISNULL(#CLIENTBRANCHNAME,C2.Description)+'%')AND
U.SalesmanName LIKE('%'+ISNULL(#USERNAME,U.SalesmanName)+'%')
GROUP BY
--CONVERT(VARCHAR, H.TrxDate, 101),
H.UserCode,U.SALESMANNAME,H.TRXDATE,D.itemcode,I.Description,d.ItemGroupLevel5,
B.Description, H.ClientCode,C1.Description,H.ClientBranchCode,C2.Description, C2.SubChannelCode
ORDER BY H.TrxDate
where #StartDate = '03/20/2017' and #EndDate = '03/21/2017' are the parameters of the stored procedure.
In my code this is how it looks:
var salesDataQuery = SalesDataModel.FromSql("exec SALESREPORTFORWEB '#StartDate='#StartDate, '#EndData='#EndData",
new SqlParameter("#StartDate", startdate),
new SqlParameter("#EndData", enddate));
But this code throws an error:
Invalid syntax error near '#StartDate='
Can somebody help me make the right stored procedure call?
Many thanks!
How about cropping parameters form exec like that:
var salesDataQuery = SalesDataModel.FromSql("exec SALESREPORTFORWEB #StartDate, #EndDate",
new SqlParameter("#StartDate", startdate),
new SqlParameter("#EndData", enddate));
Edit: added parameters to procedure.

How to Pass null value to stored procedure in sql

This is my stored procedure which take input from listbox and display records related to selected item. but if i do not select anything from listbox then it need to display all records which is no happened.
This is my Stored Procedure
USE [MyDb]
GO
/****** Object: StoredProcedure [dbo].[usp_SearchCAMAFunctionalObsolescence] Script Date: 10/18/2016 12:30:08 PM ******/
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
ALTER PROCEDURE [dbo].[usp_SearchCAMAFunctionalObsolescence]
#section as nvarchar(max),
#quality as nvarchar(max),
#style as nvarchar(max)
As
Begin
set nocount on;
Declare #Where as varchar(max)
Declare #Select as varchar(max)
Set #Select = ' Distinct vi.struct_no as structure,a.assesmt_no as assessment,a.parcel_no as parcel, o.own_last+'' , ''+o.own_first as taxpayer, id.year_built as built, id.effect_age as age, id.mkt_adj as fo, vi.aprais_val as mktvalue
From assessments a
inner join parcel p on a.parcel_no = p.parcel_no
inner join valueimp vi on vi.assesmt_no = a.assesmt_no
inner join owner o on o.id = a.owner_id
inner join imp_details id on id.improvementId = vi.id and (id.isdeleted is null or id.isdeleted = 0)
inner join quality_details qd on qd.quality_id = id.quality_id
inner join section_details sd on sd.section_id = id.section_id
inner join style_details stdl on stdl.style_id = id.style_id'
Set #Where = ' where (' + #section + ' is null or sd.section_id = ' + #section + ') and (' + #quality + ' is null or qd.quality_id = ' + #quality + ') and (' + #style + ' is null or stdl.style_id = ' + #style + ')'
DECLARE #QUERY NVARCHAR(MAX)
SET #QUERY= 'Select '+ #SELECT + #WHERE
print #QUERY
EXEC sp_executesql #QUERY , N'#section as int ,#quality as int,#style as int' ,#section ,#quality,#style
END
if i execute stored procedure in this way
// EXEC usp_SearchCAMAFunctionalObsolescence 'null','null','null'
it display all records.
but i need to execute stored procedure in this way
// EXEC usp_SearchCAMAFunctionalObsolescence null,null,null
and it not display anything
You don't need a dynamic sql for this purpose. Use IFNULL in the WHERE statements,if you are using mysql.(for SQL Server use ISNULL and for oracle use NVL instead.)
If the input variable is null,then the script will return the actual column value.
USE [MyDb]
GO
/****** Object: StoredProcedure [dbo].[usp_SearchCAMAFunctionalObsolescence] Script Date: 10/18/2016 12:30:08 PM ******/
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
ALTER PROCEDURE [dbo].[usp_SearchCAMAFunctionalObsolescence]
#section as nvarchar(max),
#quality as nvarchar(max),
#style as nvarchar(max)
As
Begin
set nocount on;
SELECT Distinct vi.struct_no as structure,a.assesmt_no as assessment,a.parcel_no as parcel, o.own_last+'' , ''+o.own_first as taxpayer, id.year_built as built, id.effect_age as age, id.mkt_adj as fo, vi.aprais_val as mktvalue
From assessments a
inner join parcel p on a.parcel_no = p.parcel_no
inner join valueimp vi on vi.assesmt_no = a.assesmt_no
inner join owner o on o.id = a.owner_id
inner join imp_details id on id.improvementId = vi.id and (id.isdeleted is null or id.isdeleted = 0)
inner join quality_details qd on qd.quality_id = id.quality_id
inner join section_details sd on sd.section_id = id.section_id
inner join style_details stdl on stdl.style_id = id.style_id
WHERE sd.section_id =IFNULL(#section,sd.section_id)
AND qd.quality_id = IFNULL(#quality,qd.quality_id)
AND stdl.style_id = IFNULL(#style,stdl.style_id )
END
Why not create a Stored Proc that returns unfiltered results and then call that in your code when no selection is made?
CREATE PROCEDURE [dbo].[usp_SearchCAMAFunctionalObsolescenceUnfiltered]
As
Begin
set nocount on;
SELEcT Distinct vi.struct_no as structure,a.assesmt_no as assessment,a.parcel_no as parcel, o.own_last+'' , ''+o.own_first as taxpayer, id.year_built as built, id.effect_age as age, id.mkt_adj as fo, vi.aprais_val as mktvalue
From assessments a
inner join parcel p on a.parcel_no = p.parcel_no
inner join valueimp vi on vi.assesmt_no = a.assesmt_no
inner join owner o on o.id = a.owner_id
inner join imp_details id on id.improvementId = vi.id and (id.isdeleted is null or id.isdeleted = 0)
inner join quality_details qd on qd.quality_id = id.quality_id
inner join section_details sd on sd.section_id = id.section_id
inner join style_details stdl on stdl.style_id = id.style_id
END

Stored Procedure returns exception in .net but runs fine in sql server c# winforms

Why does the following stored proecedure cause problems in .net c# its basically used for the nature of a report of benefits on screen readonly it works fine in sql server when i tick pass null value for start date and end date but when try to do the same on my adapter fill below it throws an exception
procedure :
public virtual EmployeeBenefitDataset GetBenefitsRecords(int id)
{
try
{
EmployeeBenefitDataset ds = new EmployeeBenefitDataset();
using (BenefitTableAdapter adpt = new BenefitTableAdapter())
{
adpt.Connection.ConnectionString = DataAccessLogicHelper.PamsConnectionString;
adpt.Fill(ds.BenefitRecords, id, 4, null,null);
}
return ds;
}
catch (Exception ex)
{
Logger.ErrorEntry(ex);
throw ex;
}
stored proecdure
GO
/****** Object: StoredProcedure [dbo].[hms_GetBenefitRecordsDetails] Script Date: 09/09/2013 14:09:42 ******/
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
ALTER PROCEDURE [dbo].[hms_GetBenefitRecordsDetails]
(
#empno int,
#type int,
#stardate datetime,
#enddate datetime
)
AS
SET NOCOUNT ON;
IF NOT #stardate IS NULL
begin
SELECT benefit.emp_no, benefit.record_id, benefit.contract_id, benefit.career_id, benefit.date_from, benefit.date_to, benefit.benefit_type, benefit.monthly_value,
benefit.benefit_provider, benefit.level_of_cover, benefit.previous_monthly_cost, benefit.benefit_change_details, benefit.current_benefit, benefit.notes,
benefit.level_description, benefit.monthly_annual, benefit.cover_level, benefit.qualifying_reason, benefit_cover_level.desc_ AS benefitcoverdescription,
benefit_provider.desc_ AS benefitproviderdescription,benefit_type.desc_ as benefittypedescription ,employee.benefit_annual_amount,employee.benefit_salary_option,employee.benefit_value
FROM benefit INNER JOIN
benefit_cover_level ON benefit.cover_level = benefit_cover_level.code INNER JOIN
benefit_provider ON benefit.benefit_provider = benefit_provider.code INNER JOIN
benefit_type ON benefit.benefit_type = benefit_type.code
INNER JOIN employee on benefit.emp_no = #empno
where benefit.emp_no= #empno or employee.emp_no= benefit.emp_no
and benefit.benefit_type = #type
end
else
begin
SELECT benefit.emp_no, benefit.record_id, benefit.contract_id, benefit.career_id, benefit.date_from, benefit.date_to, benefit.benefit_type, benefit.monthly_value,
benefit.benefit_provider, benefit.level_of_cover, benefit.previous_monthly_cost, benefit.benefit_change_details, benefit.current_benefit, benefit.notes,
benefit.level_description, benefit.monthly_annual, benefit.cover_level, benefit.qualifying_reason, benefit_cover_level.desc_ AS benefitcoverdescription,
benefit_provider.desc_ AS benefitproviderdescription,benefit_type.desc_ as benefittypedescription ,employee.benefit_annual_amount,employee.benefit_salary_option,employee.benefit_value
FROM benefit INNER JOIN
benefit_cover_level ON benefit.cover_level = benefit_cover_level.code INNER JOIN
benefit_provider ON benefit.benefit_provider = benefit_provider.code INNER JOIN
benefit_type ON benefit.benefit_type = benefit_type.code
INNER JOIN employee on benefit.emp_no = #empno
where benefit.emp_no= #empno and employee.emp_no= benefit.emp_no
end
IF NOT #stardate IS NULL
begin
SELECT benefit.emp_no, benefit.record_id, benefit.contract_id, benefit.career_id, benefit.date_from, benefit.date_to, benefit.benefit_type, benefit.monthly_value,
benefit.benefit_provider, benefit.level_of_cover, benefit.previous_monthly_cost, benefit.benefit_change_details, benefit.current_benefit, benefit.notes,
benefit.level_description, benefit.monthly_annual, benefit.cover_level, benefit.qualifying_reason, benefit_cover_level.desc_ AS benefitcoverdescription,
benefit_provider.desc_ AS benefitproviderdescription,benefit_type.desc_ as benefittypedescription ,employee.benefit_annual_amount,employee.benefit_salary_option,employee.benefit_value
FROM benefit INNER JOIN
benefit_cover_level ON benefit.cover_level = benefit_cover_level.code INNER JOIN
benefit_provider ON benefit.benefit_provider = benefit_provider.code INNER JOIN
benefit_type ON benefit.benefit_type = benefit_type.code
INNER JOIN employee on benefit.emp_no = #empno
where benefit.emp_no= #empno and employee.emp_no= benefit.emp_no and
benefit.benefit_type = #type and
benefit.date_from >= #stardate and benefit.date_to <= #enddate
end
The minimum and maximum dates that SQL and C# use are different... this could account for you 'only .NET' error. These are the minimum and maximum values that SQL can handle:
private DateTime minSqlValue = new DateTime(1753, 1, 1, 0, 0, 0);
private DateTime maxSqlValue = DateTime.MaxValue.AddMilliseconds(-3);
Please check the dates that are being used and update them if they are outside this range.
When you select the checkbox to pass null values, then it explicitly pass the NULL values alongwith the parameters. In your current code, you are not even passing the parameters that is why the exception.
In current form your stored procedure is not ready to accept NULL values for startdate and enddate, you should modify your procedure as:
#stardate datetime = NULL,
#enddate datetime = NULL
For passing NULL DateTime from C# use DateTime? or Nullable<DateTime>, which supports Null values.
This is correct, the problem is that ADO.NET see you passed an null value, which it has as a System.Object, to call a procedure for a SQL Server DateTime parameter, which it will try to map to System.DateTime, not System.Nullable<System.DateTime>. Because System.DateTime is not nullable, it will take default(DateTime) to send to the procedure. default(DateTime) in .NET is "01/01/0001 00:00:00.00", which does not match SQL Server's minimum DateTime value
Change your stored procedure to use DateTime2.

Stored procedure with nullable value in date field

In this stored procedure , in a where condition if #startDate and #EndDate values are null then how it can be handle using COALESCE.
CREATE PROCEDURE dbo.SP_ManageLeaveSearch
#StartDate datetime,
#EndDate datetime,
#UserName CHAR(100),
#MarketID INT
AS
BEGIN
SELECT d1.UserName,c1.HouseName,c.StartDate,c.EndDate
FROM table1 c
Inner JOIN table2 d1 ON c.UserID = d1.UserID
WHERE
(
(
(#StartDate BETWEEN StartDate AND EndDate)
OR
(#EndDate BETWEEN StartDate AND EndDate)
OR
(
(#StartDate <= Startdate AND #EndDate>=EndDate)
)
)
AND
(
d1.UserName = COALESCE(#UserName, d1.UserName)
)
)
END
Thnaks in advance.
This should work for you:
CREATE PROCEDURE dbo.ManageLeaveSearch
#StartDate datetime = NULL,
#EndDate datetime = NULL,
#UserName CHAR(100) = NULL,
#MarketID INT
AS
BEGIN
SELECT d1.UserName,c1.HouseName,c.StartDate,c.EndDate
FROM table1 c
Inner JOIN table2 d1 ON c.UserID = d1.UserID
WHERE
COALESCE(#StartDate,StartDate) <= EndDate AND
StartDate <= COALESCE(#EndDate,EndDate) AND
d1.UserName = COALESCE(#UserName, d1.UserName)
END
Notes:
Don't name stored procedures with an sp_ prefix - it's reserved for Microsoft's system procedures.
I've gone with simpler conditions for determining an overlap exists. An overlap exists between two ranges if range 1 starts before range 2 ends, and range 2 starts before range 1 ends.
I've specified defaults for those parameters that should be nullable.
Try this one -
CREATE PROCEDURE dbo.usp_ManageLeaveSearch
#StartDate DATETIME,
#EndDate DATETIME,
#UserName CHAR(100),
#MarketID INT
AS BEGIN
SELECT
d1.UserName
, c.HouseName
, c.StartDate
, c.EndDate
FROM dbo.table1 c
JOIN dbo.table2 d1 ON c.UserID = d1.UserID
WHERE d1.UserName = ISNULL(#UserName, d1.UserName)
AND (
ISNULL(#StartDate, StartDate) BETWEEN StartDate AND EndDate
OR
ISNULL(#EndDate, EndDate) BETWEEN StartDate AND EndDate
)
END
You've overly complicated things. This should work for you, and is as simple of a query as I know of. I prefer this syntax because in most of my use cases, the ...OR #UserName IS NULL can be removed from the query before it is even executed thereby making a very simple, fast execution.
CREATE PROCEDURE dbo.SP_ManageLeaveSearch
#StartDate datetime,
#EndDate datetime,
#UserName CHAR(100),
#MarketID INT
AS
BEGIN
SELECT d1.UserName,c1.HouseName,c.StartDate,c.EndDate
FROM table1 c
JOIN table2 d1
ON c.UserID = d1.UserID
WHERE (#StartDate<=EndDate OR #StartDate IS NULL)
AND (#EndDate>=StartDate OR #EndDate IS NULL)
AND (d1.UserName = #UserName OR #UserName IS NULL)
END

how to combine result of stored procedure which returns two results in SQL 2005?

Hey i'm kind new in Stored procs, i have procedure like
ALTER procedure [dbo].[list_of_employee]
(
#employee_id int
)
as
begin
select *from project_employee_rel PE
inner join employee_details E on E.employee_id=PE.employee_id
inner join project_details P on P.project_id=PE.project_id
where PE.employee_id=#employee_id
select * from employee_details
where employee_id=#employee_id
end
It returns two results separately
I want result like 'if first query returns empty rows or null then second query get executed otherwise not
Plz help me
thanks in advance
Try this
ALTER procedure [dbo].[list_of_employee]
(
#employee_id int
)
as
BEGIN
DECLARE #Count int
SET #Count = select COUNT(PRIMARYKEY COLUMN) from project_employee_rel PE
inner join employee_details E on E.employee_id=PE.employee_id
inner join project_details P on P.project_id=PE.project_id
where PE.employee_id=#employee_id
IF (#Count>0)
BEGIN
select *from project_employee_rel PE
inner join employee_details E on E.employee_id=PE.employee_id
inner join project_details P on P.project_id=PE.project_id
where PE.employee_id=#employee_id
END
ELSE
BEGIN
select * from employee_details
where employee_id=#employee_id
END
END
IF Check Count of your first query
return result set
ELSE
return other result set
END

Categories

Resources