dynamic pivot with parameter passed in - sql

I have created this stored procedure that works when hard coded
(in the where clause at #WeekStart and #WeekEnd),
If I try to add parameters to the query #WeekStart and #WeekEnd I get the following error:
Must declare the scalar variable "#WeekStart".
My goal is to do do something like this instead of having to hard code it:
exec dbo.GetTotals #WeekStart='2022-04-11',#WeekEnd='2022-04-25'
The stored procedure:
CREATE PROCEDURE [dbo].[GetTotals]
#WeekStart Date,
#WeekEnd Date
AS
begin
set nocount on;
--get row names
DECLARE
#columns NVARCHAR(MAX) = '',
#sql NVARCHAR(MAX) = '';
-- select the category names
SELECT
#columns+=QUOTENAME(DepartmentName) + ','
FROM
DepartmentTable
ORDER BY
DepartmentName;
--set#colums variable
SET #columns = LEFT(#columns, LEN(#columns) - 1);
-- construct dynamic SQL
SET #sql ='
SELECT * FROM
(
select
JobCode,
DepartmentName,
(COALESCE(MonTime, 0)+COALESCE(TueTime, 0)+COALESCE(WenTime, 0)+COALESCE(ThurTime, 0)+COALESCE(FriTime, 0)
+COALESCE(SatTime, 0)+COALESCE(SunTime, 0)) as total
from TimeSheetTable
INNER JOIN DepartmentTable ON TimeSheetTable.DeptId=DepartmentTable.Id
inner join JobCodeTable on TimeSheetTable.JobId=JobCodeTable.Id
--This Works--
-- Where WeekStartDate Between ''2022-04-11'' and ''2022-04-11'' --
--This is throwing an erro--
Where WeekStartDate Between #WeekStart and #WeekEnd
) t
PIVOT(
sum(total)
FOR DepartmentName IN ('+ #columns +')
)pivot_table
ORDER BY JobCode
'
---- execute the dynamic SQL
EXECUTE sp_executesql #sql;
end

exec sp_executesql #Sql, N' #WeekStart Date, #WeekEnd Date', #WeekStart = #WeekStart, #WeekEnd = #WeekEnd

Related

Handle string or binary data would be truncated

I have two procedure, one just return image in varbinary format and another one get that value and assign it in a variable. But I am getting:
String or binary data would be truncated.
Here I included both procedure below:
ALTER PROCEDURE [dbo].[Common_Sp_GetImage](#imagePath varchar(MAX), #Result VARBINARY(max) OUTPUT)
AS
BEGIN
-- SET NOCOUNT ON added to prevent extra result sets from
-- interfering with SELECT statements.
SET NOCOUNT ON;
--EXEC master..xp_cmdshell 'net use Y: \\192.168.1.175\Rack /user:192.168.1.175\SPLITPC07 IT#2022';
-- Insert statements for procedure here
DECLARE #SQL varchar(max) =
N'SELECT #Result = BulkColumn
FROM OPENROWSET(BULK ''Y:' + #imagePath + N''', SINGLE_BLOB) AS t';
EXECUTE sp_executesql #SQL, N'#Result varbinary(max) OUTPUT', #Result OUTPUT;
RETURN #Result;
END
Another one is:
ALTER PROCEDURE [dbo].[Sales_Sp_MoneyRecipt]
-- Add the parameters for the stored procedure here
#CollectionId int
AS
BEGIN
-- SET NOCOUNT ON added to prevent extra result sets from
-- interfering with SELECT statements.
SET NOCOUNT ON;
-- Your insert TSQL here.
declare #CompanyImage varbinary(max)
declare #ProjectShornaliImage varbinary(max)
declare #ProjectSunvalleyImage varbinary(max)
EXEC GetImageProcedure '\Common\SwadeshLogo.jpg', #CompanyImage OUTPUT;
EXEC GetImageProcedure '\Common\ShornaliLogoEn.jpg', #ProjectShornaliImage OUTPUT;
EXEC GetImageProcedure '\Common\SunvalleyLogoEn.jpg', #ProjectSunvalleyImage OUTPUT;
select
'Money Receipt' ReportName,
dbo.GetCompanyName() as CompanyName,
dbo.GetCompanyAddress() as CompanyAddress,
ci.MRIdentity,
ci.MRNo,
ci.MRDate,
si.ApplicationId,
c.ClientName,
dbo.GetSalesMasterName(si.PlotType, 4) PlotType,
cti.CollectionTypeName CollectionType,
CONCAT(Left(ci.InstallmentFrom, 4), + '-' + DateName( month , DateAdd( month , CONVERT(int, RIGHT(ci.InstallmentFrom, 2)) , -1 ))) FromYearMonth,
CONCAT(Left(ci.InstallmentTo, 4), + '-' + DateName( month , DateAdd( month , CONVERT(int, RIGHT(ci.InstallmentTo, 2)) , -1 ))) ToYearMonth,
si.ProjectId,
Case when si.ProjectId = 1 then #ProjectShornaliImage else #ProjectSunvalleyImage end as ProjectImage,
dbo.GetProjectNameEnglish(si.ProjectId) ProjectName,
si.TotalArea,
dbo.GetMasterName(ci.MRType, 49) MRType,
ci.ChequeNo,
ci.ChequeDate,
b.BankName,
ci.Amount,
#CompanyImage as CompanyImage
from Sales_CollectionInfo ci
inner join Sales_CollectionTypeInfo cti on ci.CollectionType = cti.CollectionTypeId
inner join Sales_SaleInfo si on ci.SalesId = si.SaleId
inner join Sales_ClientInfo c on si.ClientId = c.ClientId
left join BankInfo b on ci.ChequeBank = b.Id
where ci.CollectionId = #CollectionId
END

How to declare variables in T-SQL from select statements

declare #Week nvarchar(16) = quotename(concat('Week',#CID,#SID));
declare #Week2 nvarchar(256) = concat('SELECT TOP 1 [Year],[Week] FROM',#Week,'GROUP BY [Year],[Week] ORDER BY [Year] DESC,[Week] DESC');
exec sp_executesql #Week2
how can I declare #Year and #Week respectively from the result of exec sp_executesql #Week2? (declare as in assign the result values into #year and #week)
Thanks
declare #latestyear NVARCHAR(50), #latestweek NVARCHAR(50)
declare #Week2 nvarchar(256) = 'SELECT TOP 1 #latestyear=[Year],#latestweekweek=[Week] FROM [Week45] GROUP BY [Year],[Week] ORDER BY [Year] DESC,[Week] DESC';
exec sp_executesql #Week2
PRINT #latestyear
PRINT #latestweek
The above doesn't seem to work for me
Also trying to do this in 1 select statement if possible

EXEC sp_executesql with a datetime parameter?

I'm using EXEC sp_executesql for a dynamic query in SQL Server 2016, and am stumbling on when a user wants to pass in a year. I have a datetime field called tkemdate and it is stored as a datetime field in SQL.
Although SQL stores it as datetime, the user only passes in a year parameter (2020, 2019, 2018, etc). How do I get the query accept just the year?
Here's my stored procedure, with the datetime param.
(
#tkemdate datetime
)
AS
BEGIN
Declare #SQL NVARCHAR(MAX)
Set #SQL = 'SELECT timekeep.tkinit, timekeep.tkfirst, timekeep.tklast,
year(timekeep.tkemdate) as tkemdate
FROM abc123.timekeep'
WHERE 1 = 1
IF #tkemdate IS NOT NULL
Select #SQL = #SQL + 'AND ([tkemdate] = #tkemdate)'
EXEC sp_executesql #SQL, N'#tkemdate datetime', #tkemdate
END
You can use something like this:
IF #year IS NOT NULL
Select #SQL = #SQL + ' AND (YEAR([tkemdate]) = #year)'
EXEC sp_executesql #SQL, N'#year int', #year=#year;
It is not clear where #year comes from, but you say that the user is passing in the year.
If you only want to use the year from #tkemdate then:
IF #tkemdate IS NOT NULL
Select #SQL = #SQL + ' AND (YEAR([tkemdate]) = YEAR(#tkemdate))';
EXEC sp_executesql #SQL, N'##tkemdate datetime', ##tkemdate=##tkemdate;
It could be also something like that - where Your procedure has an integer parameter representing year.
We could also add some validation to it, for example if #year is less than 1000 or greater than 2500.
CREATE PROCEDURE abc123.get_timekeep_records (
#year int
)
AS
BEGIN
SET NOCOUNT ON; -- I usually add this because of a PHP driver
DECLARE #SQL NVARCHAR(MAX)
SET #SQL = 'SELECT timekeep.tkinit, timekeep.tkfirst, timekeep.tklast,
YEAR(timekeep.tkemdate) as [tkemdate]
FROM abc123.timekeep
WHERE 1 = 1 '
-- Validation
IF #year < 1000 OR #year > 2500
RAISERROR('Invalid year: %i', 16, 1, #year)
IF #year IS NOT NULL
SELECT #SQL = #SQL + 'AND (YEAR(timekeep.tkemdate) = #year)'
EXEC sp_executesql #SQL, N'#year int', #year;
END

Dynamic query based on datetime parameter

I have a SQL Server database with date representation name like below & each database contains table A (table A having column like id, datetime, value, value1 etc).
Jan2018
Feb2018
Mar2018 and so on..
My search condition is user selected date (eg. from 01-Jan-2018 to 01-Jun-2018) which I am passing to a stored procedure (max range 6 month). I want to generate dynamic query to get data from these database based on datetime passed.
How to achieve this functionality as I found difficult to implement.
Can you try this query
CREATE PROCEDURE Myproc #FromDate DATE,
#ToDate DATE
AS
BEGIN
DECLARE #SQL NVARCHAR(max)='',
#unionall VARCHAR(10)=''
WITH cte
AS (SELECT #FromDate dt,
1 mont
UNION ALL
SELECT Dateadd(month, 1, dt) dt,
mont + 1 mont
FROM cte
WHERE mont < Datediff(month, #FromDate, #ToDate)
)
SELECT #SQL += #unionall + '
select * from ['
+ LEFT (CONVERT(VARCHAR, Datename (month, dt )), 3)
+ CONVERT (VARCHAR, Year (dt))
+ '].[dbo].[tablename]',
#unionall = ' union all '
FROM cte
PRINT #SQL
EXECUTE( #SQL)
END
You should query sys.databases to find a database you need.
Then, as you can only use static declarations of databases, you should create a textual select statement and execute it.
I tried it on my dbs and it worked.
This is my code:
declare #date varchar(20) = '2018'
declare #dbName varchar(20)
declare #sSql varchar(200)
declare #sConditions varchar(20) = ''
Set #dbName = (SELECT name FROM master.sys.databases
where name like '%' + #date + '%')
print #dbName
Select #sSql = 'Select * From ' + #dbName + '.dbo.MyDB '
--+ ' Where ' + #sConditions
Execute (#sSql)
if you need to query all that fit year. do like this:
declare #date varchar(20) = 'a'
SELECT name Into #dbnames
FROM master.sys.databases
where name like '%' + #date + '%'
this brings a table of all sutable dbs. then query each one of them using loop. like cursor
Are you looking for
CREATE PROCEDURE MyProc
#FromDate DATE,
#ToDate DATE,
#Target SysName
AS
BEGIN
DECLARE #SQL NVARCHAR(MAX)= N'SELECT * FROM [' +
#Target +
'] WHERE [Dates] >= #FromDate AND [Dates] <= #ToDate';
EXECUTE sp_executesql #SQL,
N'#FromDate DATE, #ToDate DATE',
#FromDate,
#ToDate;
END
Demo
As I now understand what you are trying to do, you can
CREATE PROCEDURE ProcName
#FromDate DATE,
#ToDate DATE
AS
BEGIN
--Declare a variable to hold the Dynamic SQL
DECLARE #SQL NVARCHAR(MAX) = N'';
--Generate the databases names
WITH CTE AS
(
SELECT #FromDate D,
1 N
UNION ALL
SELECT DATEADD(Month, N, #FromDate),
N + 1
FROM CTE
WHERE N <= DATEDIFF(Month, #FromDate, #ToDate)
)
--Build the SELECT statement
SELECT #SQL = #SQL+
N'SELECT * FROM ['+
CONVERT(VARCHAR(3), D, 100)+
CAST(YEAR(D) AS VARCHAR(4))+
'].dbo.TableName UNION ALL ' --Or UNION as you want
FROM CTE;
--Remove the last UNION ALL
SET #SQL = LEFT(#SQL, LEN(#SQL) - 10); --If UNION then just -6
--Execute the statement
EXECUTE sp_executesql #SQL;
END

Passing two values to a stored procedure?

I've written a stored procedure which is called on a link which provides a date value every time and #cg is NULL that time to filter the result on a particular date.
DECLARE #return_value int
EXEC #return_value = [dbo].[Get_Mydata]
#cg = NULL,
#tosearch = '15-05-2014'
SELECT 'Return Value' = #return_value
GO
And after first execution of the stored procedure, it gives some results and using same stored procedure.
I need to filter result by passing below parameter so this time #cg is NOT NULL.
DECLARE #return_value int
EXEC #return_value = [dbo].[Get_Mydata]
#cg = 'CUSTOMER NAME',
#tosearch = 'manish'
SELECT 'Return Value' = #return_value
GO
I'm not able to figure how should I create a dynamic where clause and add it to existing query as well as how to pass value to same parameter which already been passed as date.
More like first getting results for a particular date and then applying like filter on that result. I cannot pass different parameter that's Front end developers requirement.
This is my stored procedure and table data here. http://sqlfiddle.com/#!3/bb917
create proc Get_Mydata
(
#cg varchar(50),
#tosearch varchar(50)
)
as
begin
set nocount on
declare #sqlquery nvarchar(max)
set #sqlquery = N'select q_no, trandate, cust_name from testsp where CONVERT(Date, trandate, 103) = CONVERT(Date, ''' + #tosearch + ''' ,103)';
create table #temp1
(
q_no int,
trandate datetime,
cust_name varchar(50)
)
insert into #temp1(q_no, trandate, cust_name)
exec (#sqlquery)
select * from #temp1 as T;
set nocount off
end
What I have understood is that you want stored procedure to filter results on Date column when you pass null to #cg param and you want to filter results on Cust_name when you pass string 'Cust_Name' to your #Cg Param.
It should be fairly simple, But in any case you do not need a temp table to get the results back its just an over kill of a fairly simple query.
I would do something like this....
Pass the column name to #ColumnName Parameter, and your value to #tosearch parameter. It will build the query depending on what values you pass.
Make sure when you pass a value(Column Name) to #ColumnName.
create proc Get_Mydata
(
#ColumnName varchar(50),
#tosearch varchar(50)
)
as
begin
set nocount on;
declare #sqlquery nvarchar(max);
set #sqlquery = N' select q_no, trandate, cust_name '
+ N' from testsp '
+ N' where ' + QUOTENAME(#ColumnName) + N' = '
+ CASE
WHEN #ColumnName = 'trandate'
THEN N' CAST(#tosearch AS DATE)'
WHEN #ColumnName = 'cust_name'
THEN N' #tosearch'
ELSE N'' END
EXECUTE sp_executesql #sqlquery
,N'#tosearch varchar(50)'
,#tosearch
set nocount off;
end