ssrs Ignoring variable which is not declared - sql

This is my part of the query which i am using in the Dataset in SSRS2008
DECLARE #SERVER VARCHAR(20) = null;
Declare #curDATEFIRST as Integer = ##DATEFIRST;
SET DATEFIRST 1;
IF #a=0 AND #b>1
BEGIN
DECLARE #NewStartDate DateTime = (SELECT TOP 1 StartDate FROM UserManagerDates WHERE EmployeeID=#b ORDER BY StartDate DESC);
IF #NewStartDate>#StartDate SET #StartDate = #NewStartDate;
END
Question:
I was copying my query into dataset from ssms and when i hit refresh in dataset i only get prompted for #a and #b in define query parameters. Actually i wasn't even declaring #startdate so i was expecting #startdate variable in define query parameters tab. What changes should i make to to get prompted for #startdate along with the other two variables?

You are setting the #startdate parameter, it is supposed to be populated by SSRS instead of your query, that could be the reason you are not being prompted.
I think you want to use #startdate to populate #NewStartDate, if so try this:
DECLARE #SERVER VARCHAR(20) = null;
Declare #curDATEFIRST as Integer = ##DATEFIRST;
SET DATEFIRST 1;
IF #a=0 AND #b>1
BEGIN
DECLARE #NewStartDate DateTime =
(SELECT TOP 1 StartDate FROM UserManagerDates
WHERE EmployeeID=#b ORDER BY StartDate DESC);
IF #NewStartDate>#StartDate SET #NewStartDate = #startdate;
END

Related

Assigning variables to use in query

I am moving from Oracle to SQL Server and I am noticing differences regarding assigning variables in a query. I wonder if someone could write me a simple example of how I can do this in SSMS please?
In the example below I am looking to assign the variable #date1 at the beginning of the select statement so that I can simply change the date at the top instead of having to change it several times in the query where #date1 is used several times.
SELECT *
FROM table
where date = #date1
Thanks
Based on your example the syntax would be as follows:
DECLARE #date1 DATETIME
SET #date1 = '2017-01-01 00:00:00.000'
Then reference #date1 in your query as you have above.
More broadly, the syntax is:
DECLARE #<name of variable> <type>
SET #<name of variable> = <value>
-- Simple declares
DECLARE #Variable1 VARCHAR(100)
DECLARE #Variable2 DATE
DECLARE #VariableTable TABLE (
numberColumnName INT,
textColumnName VARCHAR(MAX))
-- Chained declares
DECLARE
#Variable3 VARCHAR(100),
#Variable4 INT
-- Declare with initiation
DECLARE #Variable5 INT = 150
DECLARE #Variable6 DATE = '2018-05-05' -- Implicit conversion (varchar to date)
DECLARE #Variable7 FLOAT = 1945.15 * 1648.12 / #Variable5 -- Expressions can be used
DECLARE #Variable8 INT = (SELECT COUNT(1) FROM sys.objects)
-- Chained declares with initiation
DECLARE
#Variable9 VARCHAR(100) = 'Afla',
#Variable10 INT = 9164 * #Variable5
-- Change variable values (without declaring)
SET #Variable1 = 'Some value'
SET #Variable2 = CONVERT(DATE, GETDATE())
For your example:
DECLARE #DateFilter DATE = '2018-05-16' -- Use ISO standard date format (yyyy-MM-dd) when you hard-code them as literals
SELECT
*
FROM
YourTable AS T
WHERE
T.DateToFilter >= #DateFilter
DECLARE #date1 DATE = '2018-04-11'
This code may be fine, but be aware of dates formats :date (Transact-SQL)
and the need of using either Date, Datetime, or Datetime2.

Multiple parameters error while creating function in SQL Server

I created a function, now rather passing static value I want to add parameter in the function but after calling function it start throwing an error:
Procedure or function dbo.hello has too many arguments specified.
Function :
Create Function dbo.hello
(#InputstartDate Date, #InputendDate Date)
Returns #attendanceTemp table(STUD_NAME VARCHAR(50),
ATTD_DATE DATE ,
attd_DATEs DATE,
Attendance VARCHAR(20))
As
Begin
Declare #startDate DATE
SET #startDate = #InputstartDate
Declare #endDate Date
SET #endDate = #InputendDate
Declare #dateDifference INT
SET #dateDifference = DATEDIFF(day, #startDate,#endDate) ;
Declare #count INT
SET #count = 0
DECLARE #myTable TABLE (STUD_ID int,
countdd int,
STUD_NAME varchar(50),
AttDate Date
)
While #count <= #dateDifference
Begin
Insert Into #myTable (STUD_ID, countdd, STUD_NAME, AttDate)
Values (1, 123, 'HAIDER', #startDate)
Set #count = #count +1
Set #startDate = DATEADD(day, 1, #startDate)
End
Insert Into #attendanceTemp
Select
tb.STUD_NAME, ATTD_DATE, tb.AttDate,
Case
When att.DETAIL Is Null
Then 'ABSENT'
When att.DETAIL = 'ATTENDACE'
Then 'PRESENT'
End As Attendance
from
#myTable tb
Left Join
ATTENDANCE att on tb.AttDate = att.ATTD_DATE
Where
att.STUD_ID = 1 or att.STUD_ID IS NULL
Return
END
Calling the function:
select *
from dbo.hello('2014-04-01', '2014-04-10');
Error:
Procedure or function dbo.hello has too many arguments specified
Possibly you first created the function with only one parameter.
Then made changes to the 'create function' script, and forgot to deploy?
I would;
1. DROP FUNCTION dbo.hello
2. CREATE FUNCTION dbo.hello, with you script
3. Try executing your function again.
The function seems to work fine (Though I cannot run a full test due to not having table 'ATTENDANCE')

Performance issue with stored procedure [closed]

Closed. This question does not meet Stack Overflow guidelines. It is not currently accepting answers.
This question does not appear to be about programming within the scope defined in the help center.
Closed 7 years ago.
Improve this question
I have a stored procedure that uses the while loop temp table and cursor by which I gets the aging balance of customer, however my SP is working fine but I have some performance concerns as its take 15 sec to produce results from a small chunk of data. I am looking for a more efficient way to do this.
Thanks in advance.
Here is my stored procedure.
CREATE TABLE #Customer_Temp (
AccountCode varchar(50),
AccountTitle varchar(50),
CurrentBalance int,
FirstBalance int,
SecondBalance int,
ThirdBalance int,
FourthBalance int,
FifthBalance int,
SixthBalance int,
SeventhBalance int,
EighthBalance int,
OpeningBalance int
)
INSERT INTO #customer_temp (AccountCode, AccountTitle, OpeningBalance)
SELECT
Customer.AccountCode,
Customer.Name,
COA.OpeningBalance
FROM Customers AS Customer
INNER JOIN ChartOfAccount AS COA
ON COA.CompanyId = #Companyid
AND COA.BusinessUnitId = #BusinessUnitId
AND COA.ChartAccount = Customer.AccountCode
--Create Table And Duplicate Customers Data In it ENDED
DECLARE #DrAmount AS int
DECLARE #CrAmount AS int
DECLARE #Balance AS int
DECLARE #FBalance AS int
DECLARE #SBalance AS int
DECLARE #TBalance AS int
DECLARE #FoBalance AS int
DECLARE #FIBalance AS int
DECLARE #SIBalance AS int
DECLARE #SEBalance AS int
DECLARE #EBalance AS int
DECLARE #FSDate AS date
DECLARE #FLDate AS date
DECLARE #SSDate AS date
DECLARE #SLDate AS date
DECLARE #TSDate AS date
DECLARE #TLDate AS date
DECLARE #FOSDate AS date
DECLARE #FOLDate AS date
DECLARE #FISDate AS date
DECLARE #FILDate AS date
DECLARE #SISDate AS date
DECLARE #SILDate AS date
DECLARE #SESDate AS date
DECLARE #SELDate AS date
DECLARE #ESDate AS date
SET #FSDate = DATEADD(DAY, -1, #StartDate)
SET #FLDate = DATEADD(DAY, -6, #FSDate)
SET #SSDate = DATEADD(DAY, -1, #FLDate)
SET #SLDate = DATEADD(DAY, -6, #SSDate)
SET #TSDate = DATEADD(DAY, -1, #SLDate)
SET #TLDate = DATEADD(DAY, -14, #TSDate)
SET #FOSDate = DATEADD(DAY, -1, #TLDate)
SET #FOLDate = DATEADD(DAY, -14, #FOSDate)
SET #FISDate = DATEADD(DAY, -1, #FOLDate)
SET #FILDate = DATEADD(DAY, -14, #FISDate)
SET #SISDate = DATEADD(DAY, -1, #FILDate)
SET #SILDate = DATEADD(DAY, -29, #SISDate)
SET #SESDate = DATEADD(DAY, -1, #SILDate)
SET #SELDate = DATEADD(DAY, -89, #SESDate)
SET #ESDate = DATEADD(DAY, -1, #SELDate)
DECLARE #TempCCode AS varchar(50)
DECLARE #TempOBalance AS float
DECLARE CustomerCursor CURSOR FOR
SELECT
AccountCode,
OpeningBalance
FROM #Customer_Temp
OPEN CustomerCursor
FETCH NEXT FROM CustomerCursor INTO #TempCCode, #TempOBalance
WHILE ##FETCH_STATUS = 0
BEGIN
EXEC #FBalance = GetBalanceOfAgingOnDate #BusinessUnitId,
#Companyid,
#TempCCode,
#FSDate,
#FLDate,
#Fyear
EXEC #SBalance = GetBalanceOfAgingOnDate #BusinessUnitId,
#Companyid,
#TempCCode,
#SSDate,
#SLDate,
#Fyear
EXEC #TBalance = GetBalanceOfAgingOnDate #BusinessUnitId,
#Companyid,
#TempCCode,
#TSDate,
#TLDate,
#Fyear
EXEC #FoBalance = GetBalanceOfAgingOnDate #BusinessUnitId,
#Companyid,
#TempCCode,
#FOSDate,
#FOLDate,
#Fyear
EXEC #FIBalance = GetBalanceOfAgingOnDate #BusinessUnitId,
#Companyid,
#TempCCode,
#FISDate,
#FILDate,
#Fyear
EXEC #SIBalance = GetBalanceOfAgingOnDate #BusinessUnitId,
#Companyid,
#TempCCode,
#SISDate,
#SILDate,
#Fyear
PRINT #SESDate
PRINT #SELDate
EXEC #SEBalance =
GetBalanceOfAgingOnDate #BusinessUnitId,
#Companyid,
#TempCCode,
#SESDate,
#SELDate,
#Fyear
EXEC #EBalance = GetBalanceOfAgingOnDate #BusinessUnitId,
#Companyid,
#TempCCode,
#ESDate,
#EndDate,
#Fyear
EXEC #Balance = GetBalanceOfAgingOnDate #BusinessUnitId,
#Companyid,
#TempCCode,
#StartDate,
#EndDate,
#Fyear
UPDATE #Customer_Temp
SET CurrentBalance = (#Balance + #TempOBalance),
FirstBalance = #FBalance,
SecondBalance = #SBalance,
ThirdBalance = #TBalance,
FourthBalance = #FoBalance,
FifthBalance = #FIBalance,
SixthBalance = #SIBalance,
SeventhBalance = #SEBalance,
EighthBalance = #EBalance
WHERE AccountCode = #TempCCode
FETCH NEXT FROM CustomerCursor INTO #TempCCode, #TempOBalance
END
CLOSE CustomerCursor
DEALLOCATE CustomerCursor
AND here is the called store procedure in cursor
CREATE PROCEDURE [dbo].[GetBalanceOfAgingOnDate]
#BusinessUnitId int,
#Companyid int,
#ChartAccount as varchar (50),
#StartDate as DateTime,
#EndDate as DateTime,
#Fyear as varchar(50)
AS BEGIN
Declare #DrAmount as int
Declare #CrAmount as int
Declare #Balance as int
set #DrAmount=(select sum(Dr_Amount) from AccountVocherMaster AS AM ,
AccountVocherChild AS AC Where AM.CompanyId = #Companyid AND
AM.BusinessUnitId = #BusinessUnitId AND AM.FYear = #Fyear AND
AM.VocherId = AC.VocherId AND AC.AccountCode=#ChartAccount AND
AC.CreatedOn Between #EndDate AND #StartDate);
set #CrAmount=(select sum(Cr_Amount) from AccountVocherMaster AS AM ,
AccountVocherChild AS AC Where AM.CompanyId = #Companyid AND
AM.BusinessUnitId = #BusinessUnitId AND AM.FYear = #Fyear AND
AM.VocherId = AC.VocherId AND AC.AccountCode=#ChartAccount AND
AC.CreatedOn Between #EndDate AND #StartDate);
set #Balance = #DrAmount - #CrAmount ;
return ISNULL(#Balance,0)
END
make cursor a local variable DECLARE #CustomerCursor CURSOR, ensure it is not dynamic and does not reflect updates to cursor's source tables SET #CustomerCursor = CURSOR FAST_FORWARD FOR, in the end update by current cursor position, avoid additional search UPDATE #Customer_Temp SET ... WHERE CURRENT OF #CustomerCursor
obtain aggregates of different columns for similar conditions by a single select select #DrAmount = sum(Dr_Amount), #CrAmount = sum(Cr_Amount)
and more of it: select #Balance = sum(Dr_Amount) - sum(Cr_Amount)
avoid ancient-style joining by comma, write inner or outer joins, put joining conditions into ON clause, put filtering into WHERE clause
avoid thinking of SQL as a regular programming language like PHP or Pascal; it is result-set oriented; try making INLINE TABLE FUNCTION instead of procedure (GetBalanceOfAgingOnDate) - this will make you able to join to that from your queries; tip: do not make it scalar-valued or table-valued function. Look at your aggregation sp and how it is used. For each row (company) you call that sp again and again, and aggregate some values inside it. Why not to GROUP BY company and BusinessUnitID, run a single select from AccountVocherMaster and join it to your #Customer_Temp? Why not to aggregate summary for different periods by a single query? Look again: you have a list of companies, an aggregation query that provides some summarized values grouped by companies... why do you still have a cursor at all? it's a single query job
if you have lots of data and filtering by dates is the only way that makes it run fast - make not a single query, make 10 queries. this anyway will be much better than 10*2*[N companies] Actually period required is well determined - max range is [#StartDate-180, #StartDate] - and it looks like a single query is a good idea again. In some cases, if your data is very big, cursor and filtering by a scalar values may still be a good change to improve performance, thus you may still want to filter by a single CompanyID - ok, but the data you aggregate is still located in fixed date range in the same two tables - AccountVocherMaster and AccountVocherChild; loop through companies, run single aggregation query inside the cursor
there is absolutely nothing smart in your GetBalanceOfAgingOnDate's sources - don't know why you keep it as a separate module
there must be a transaction around it
Your problem is that you do not think SQL and try to be smart - you write procedural code, which SQL Server has to execute one by one INSTEAD of working in set and letting the query optimizer figure out how to do that most efficient.
Cursors and procedures are generally slow elements. You are better to forumulate this in as few atomic SQL statements as possible, even if the statements are a page or two long. Then the query optimizer can figure out how to achieve this result most efficient.
In your case, the second SP gets called repeatedly in the cursor - there are likely ways to achieve this better. In one or a lot less calls.
Hopefully this can start you down the path. There is a lot in your question, so I may not (a) understand everything here and (b) address every part, but hopefully you can take it from here. I don't see the need for any procedures or loops. Give this a try, I've commented some for context:
/* Construct a temp table to store all balance dates (and respective names) */
CREATE TABLE #BalanceDates (BalanceName VARCHAR(20), StartDate DATETIME, EndDate DATETIME);
INSERT INTO BalanceDates VALUES ('FirstBalance',DATEADD(DAY,-1,#StartDate),DATEADD(DAY,-6,#StartDate));
-- And so on with remaining inserts...
/* Create a denormalized table of all balances */
SELECT
[FirstBalance],
[SecondBalance],
...
INTO
#Balances
FROM
(
SELECT
BD.BalanceName,
ISNULL(SUM(Dr_Amount) - SUM(Cr_Amount),0) AS BalanceAmount
FROM
#BalanceDates BD
LEFT JOIN
AccountVocherChild AC
ON (AC.CreatedOn BETWEEN BD.StartDate AND BD.EndDate)
LEFT JOIN
AccountVocherMaster AM
ON (AM.VocherId = AC.VocherId)
WHERE
AM.CompanyId = #Companyid AND
AM.BusinessUnitId = #BusinessUnitId AND
AM.FYear = #Fyear AND
AC.AccountCode = #ChartAccount
GROUP BY
BD.BalanceName
) data
PIVOT
(
AVG(BalanceAmount)
FOR BalanceName IN ([FirstBalance],[SecondBalance],...)
) pvt;
/* Update the table accordingly */
UPDATE tgt
SET
FirstBalance = src.FirstBalance,
SecondBalance = src.SecondBalance,
...
FROM #Customer_Temp tgt
JOIN #Balances src
ON (1 = 1);

How to pass dynamic View name in SQL stored procedure without using a dynamic query?

Here is my stored procedure below. I am concatenating #CultureCode paramter along with view name which is [_0002HR_EmployeeNames_en-US_View]. The part en-US will be passed through a parameter named as #CultureCode. Is there any way to do so because i have requirement not to use dynamic query. Thank you.
CREATE PROCEDURE [dbo].[_001HR_Report_Loans] (#Parameters VARCHAR(max))
AS
DECLARE #ReportOption VARCHAR(5) SET #ReportOption = [dbo].DB_Split(#Parameters, 1)
DECLARE #CultureCode VARCHAR(10) SET #CultureCode = [dbo].DB_Split(#Parameters, 2)
DECLARE #ShowItems VARCHAR(5) SET #ShowItems = [dbo].DB_Split(#Parameters, 3)
DECLARE #StartDate NVARCHAR(8) SET #StartDate = [dbo].DB_Split(#Parameters, 4)
DECLARE #EndDate NVARCHAR(8) SET #EndDate = [dbo].DB_Split(#Parameters, 5)
DECLARE #EmployeeCode NVARCHAR(30) SET #EmployeeCode = [dbo].DB_Split(#Parameters, 6)
DECLARE #BranchCode NVARCHAR(30) SET #BranchCode = [dbo].DB_Split(#Parameters, 7)
--IF #StartDate = ''
-- SET #StartDate = NULL
SELECT HR.*, EN.[Name] AS EmployeeName
FROM [0002HR_EmployeeLoans] HR
LEFT JOIN [_0002HR_EmployeeNames_ + '#CultureCode' +_View] EN ON HR.EmployeeCode = EN.EmployeeCode
LEFT JOIN [_0002HR_EmployeePackagesView] EP ON EP.EmployeeCode = HR.EmployeeCode
WHERE
(HR.EmployeeCode = #EmployeeCode OR #EmployeeCode IS NULL)
AND
(EP.BranchCode = #BranchCode OR #BranchCode IS NULL)
AND
(HR.Date BETWEEN #StartDate AND #EndDate OR #StartDate IS NULL AND #EndDate IS NULL)
AND
(HR.Date >= #StartDate OR #StartDate IS NULL)
AND
(HR.Date <= #EndDate OR #EndDate IS NULL)
This is not possible in T-SQL so far. Things like TOP clauses, table or column names can not be parameterized.
One way would be to create a union over all possible tables/views, add a new column that matches the table/view name and filter that.
Like this:
SELECT * FROM
(
SELECT 'Table1' as TableName, t1.* FROM Table1 t1 WHERE ...
UNION ALL
SELECT 'Table2' as TableName, t2.* FROM Table2 t2 WHERE ...
) tmp
WHERE TableName = #tableName
Another (and possibly the most "clean" way) would be to only have one single table and make the culture a column in that table, so you only need to pass the correct culture string to filter over that column.
So you have a view per language. They are getting the data from the tables for their particular language. But now you want to write a procedure that is not language-specific.
The solution seems simple: Don't use the language views, but access the tables directly instead. (Or build an all-languages view which you query with where language = #language.)

Select statement with a Split function

I am using a select split function in stored procedure to pass a multiple selection IDS like below .
SELECT Status AS ClientInbox, COUNT(submitTime) AS CountStatus
FROM dbo.ClientInbox with (nolock) join debtor with (nolock) on ClientInbox.debtorid = debtor.id
WHERE (submitTime >= #fromDate and submittime <= #toDate)
and debtor.clientid IN (SELECT ID FROM [dbo].[split_IDs] (#clientid,','))
GROUP BY Status
Where [dbo].[split_IDs] is a function. My problem is while testing, when i replcae the variable #clientid with a set of setrings like ('1,2,3,4,5'), the query returns the required records. But when i run the procedure from VS, it does not return the exact records. I try to figure out what the problem is by executing the procedure in the SQL server as below
USE [Volare_2005]
GO
DECLARE #return_value int
DECLARE #fromDate datetime
DECLARE #toDate datetime
EXEC #return_value = [dbo].[GetSMSReportDate]
#fromDate = '2000-04-06T12:23:45',
#toDate = '2013-10-22T21:10:12',
#option = 0 ,
#collectorid = 0,
#supervisorid = 0,
#clientid = N'95,1'
--SELECT 'Return Value' = #return_value
GO
It fails the return the records as well. However it works fine when i run the query by replcaing the variable #clientid in the procedure. I am not sure were i go wrong. Please any help would be appreciate