SQL Sproc Parameters: Setting Default Date value - sql

I am trying to create a Stored Procedure that will be used for a Report and I want the 2 date parameters to have a DEFAULT value of today's date and 1 month prior.
Is the below the proper way to do this? I was reading elsewhere that I should use COALESCE...(SEE HERE)This is a touchy production system so I wanted to double check before I went forward.
CREATE PROCEDURE spCaseNoteReport
-- Add the parameters for the stored procedure here
#ContactStartDate DateTime = null,
#ContactEndDate DateTime = null
AS
IF #ContactStartDate is null
SET #ContactStartDate = dateadd(m,-1, CONVERT(date, GETDATE()))
IF #ContactEndDate is null
SET #ContactEndDate = CONVERT(date, GETDATE())
BEGIN
-- SET NOCOUNT ON added to prevent extra result sets from
-- interfering with SELECT statements.
SET NOCOUNT ON;
-- Insert statements for procedure here
SELECT (id.LastName + ', ' + id.FirstName) AS 'MemberName'
,c.ContactDate
,Li.ItemDescription AS 'Location'
,c.PresentAtContact
,c.ContactDetails
,c.InsertUser
,c.TimeSpentUnits
FROM dbo.tblCaseNotes c
inner join dbo.tblIdentificationMap id
on c.PersonID = id.PersonID
left outer join dbo.tblCaseNoteContactLocation L
on c.Casenoteid = L.Casenoteid
inner join dbo.tblCaseNotesMaintItem Li
on L.ContactLocationID = Li.ItemID
WHERE c.ContactDate BETWEEN #ContactStartDate AND #ContactEndDate
ORDER BY MemberName, c.ContactDate, c.InsertUser
END
continued
So when I actually tried to run the CREATE PROCEDURE for this I get the following errors -->
Msg 243, Level 16, State 1, Procedure spCaseNoteReport, Line 12
Type date is not a defined system type.
Msg 243, Level 16, State 1, Procedure spCaseNoteReport, Line 14
Type date is not a defined system type.

Nothing wrong with this approach. I use it myself.
Parameter defaults can only be constants or udfs so the alternative is to use udfs which honestly doesn't really help.
Edit: best way to remove a time component from datetime
DATEADD(day, DATEDIFF(day, 0, GETDATE()), 0)
See this excellent SO Q+A "Most efficient way in SQL Server to get date from date+time?" (not mine!)

Related

Issue with result set from stored procedure report generation

I have a Visual studio based stored procedure that generates a report for a monthly audit process. In the database being queried, all data for each month lives in its own individual table (Contacts_month_1, Contacts_month_2, etc.)
The SQL used in this report generation has some minor logic included, to allow it to work dynamically, rather than use hard coded dates. The problem arose at the start of January 2017, when I started receiving not just the results for the prior month, but additionally the prior year as well. To be specific, the audit report for December 2016 included data for both 12/2016 and 12/2015. Initially I thought it was a fluke of some kind based on the turn of the year, and we have not had this automated process during the turn as of yet. Unfortunately when I came in to the office today, inside the output file for January 2017, I also received the results for January 2016.
I attempted to include a year check to the process, however I am still getting the same result output. Any ideas would be appreciated.
Declare #GetMonth TinyInt
,#SessionTable varchar(50)
,#ContactTable varchar(50)
,#TableVersion varchar(2)
Declare #GetYear SmallInt
,#SessionTable_year varchar(50)
,#ContactTable_year varchar(50)
,#TableVersion_year varchar(4)
Set #GetMonth=MONTH(cast(GetDate() as Datetime))-1
Set #GetYear=YEAR(cast(GetDate() as Datetime))
If (#getmonth=0) Set #GetMonth=12 + (#GetYear-1)
Set #TableVersion=CAST(#getMonth as varchar(2))
Set #SessionTable='[CentralDWH].[dbo].[Sessions_month_' +#tableversion +']'
Set #ContactTable ='[CentralDWH].[dbo].[Contacts_month_' +#tableversion +']'
-- Select #GetMonth,#GetYear (DEBUGGING STATEMENT)
-- Select #SessionTable,#ContactTable (DEBUGGING STATEMENT)
Exec('SELECT [PBX_id] as AgentID
,[p22_value] as Skill
,''Athens'' as Location
,Convert(varchar(20),c.[local_start_time],120) as local_start_time
,convert(varchar(20),c.[local_end_time],120) as local_end_time
,U.[USER_NAME]
,call_id
FROM '+#SessionTable +' S
Inner join dbo.Users U on S.user_key=U.user_key
inner Join '+ #ContactTable+' C on S.contact_key=C.contact_key
Where is_screen > 0
And Unit_Num between 398003 and 398005
and P22_value is not null
and c.[local_start_time] > ' + #GetYear
+ ' order by local_start_time')
As I understand, the #GetMonth variable is used for returning the previous month
Set #GetMonth = MONTH(CAST(GetDate() AS Datetime)) - 1
After a quick look after you procedure my first issue was this line of code:
IF (#getmonth = 0)
SET #GetMonth = 12 + (#GetYear - 1)
I don't understand why are you setting the #GetMonth variable to 12 + current year -1 and I assume this is the cause to the problem.
Did you want to get the 12th month of the previous year when the current month is 1 (January)? If yes then you can easily change the If block to
If #GetMonth = 0
Begin
Set #GetMonth = 12
Set #GetYear = #GetYear - 1
End
Other issues:
It's recommended to keep the consistency of the names of the variables #GetMonth, #getmonth, this will cause an error if the database collation is case sensitive.
#GetMonth is declared as TinyInt and this will cause an arithmetic overflow if you try to store the year
I recommend testing the dynamic SQL statement that you are composing here with some hard coded values to check the results returned, you can use January and 2016 to check if the actual issue in your procedure or it's in your query.
Hope it helps
Thanks for your help, I figured out the root of the problem, and it was because i was not casting the GetYear as a varchar when trying to run the T-SQL statement. This in turn caused the variable to be completely ignored. I also cleaned up the query a little bit after realizing i was goofing up pretty hard.
Below is the cleaned up functional query, so that it may help someone in the future:
Declare #GetMonth SmallInt,
#SessionTable varchar(50),
#ContactTable varchar(50),
#TableVersion varchar(2),
#GetYear SmallInt,
#YearCheck varchar(4)
Set #GetMonth=MONTH(cast(GetDate() as Datetime))-1
Set #GetYear=YEAR(cast(GetDate() as Datetime))-1
If (#GetMonth=0)
Begin
Set #GetMonth =12
Set #GetYear =#GetYear - 1
End
Set #TableVersion=CAST(#GetMonth as varchar(2))
Set #SessionTable='[CentralDWH].[dbo].[Sessions_month_' +#tableversion +']'
Set #ContactTable ='[CentralDWH].[dbo].[Contacts_month_' +#tableversion +']'
Set #YearCheck=CAST(#GetYear as varchar(4))
--Select #GetMonth,#GetYear,#YearCheck (DEBUGGING STATEMENT)
-- Select #SessionTable,#ContactTable (DEBUGGING STATEMENT)
Exec('SELECT
[PBX_id] as AgentID,
[p22_value] as Skill,
''Athens'' as Location,
Convert(varchar(20),c.[local_start_time],120) as local_start_time,
convert(varchar(20),c.[local_end_time],120) as local_end_time,
U.[USER_NAME],
call_id
FROM '+#SessionTable +' S
Inner join dbo.Users U on S.user_key=U.user_key
inner Join '+ #ContactTable+' C on S.contact_key=C.contact_key
Where is_screen>0
And Unit_Num between 398003 and 398005
And P22_value is not null
And year(c.[local_start_time]) > '+#YearCheck+'
order by local_start_time')
Once I cleaned all this up and remembered to cast the year properly, everything fell into place.

Extracting a portion of a value out of a database column using SQL server

I'm trying to extract a portion of a value out of a database column using SQL server.
The example below works in a simple context with a varchar field. The result is: &kickstart& which is what I want.
I now want to do the same when retrieving a column from the database.
But SQL does not like what I am doing. I'm thinking it is something easy that I am not seeing.
Declare #FileName varchar(20) = '&kickstart&.cfg'
Declare #StartPos integer = 0
Declare #FileNameNoExt varchar(20)
SELECT #FileNameNoExt = Left(#FileName,( (charindex('.', #FileName, 0)) - 1))
SELECT #FileNameNoExt
Here is the SQL statement that I can't seem to get to work for me:
Declare #FileNameNoExt as varchar(20)
SELECT
i.InstallFileType AS InstallFileType,
o.OSlabel AS OSLabel,
SELECT #FileNameNoExt = (LEFT(oi.FIleName,( (charindex('.', oi.FIleName, 0) ) - 1) )) AS FileNameNoExt,
oi.FIleName AS FIleName
FROM
dbo.OperatingSystemInstallFiles oi
JOIN dbo.InstallFileTypes i ON oi.InstallFileTypeId = i.InstallFileTypeId
JOIN dbo.OperatingSystems o ON oi.OperatingSystemId = o.OperatingSystemId
Why do you need the variable at all? What's wrong with:
SELECT
i.InstallFileType AS InstallFileType,
o.OSlabel AS OSLabel,
LEFT(oi.FIleName,( (charindex('.', oi.FIleName, 0) ) - 1) ) AS FileNameNoExt,
oi.FIleName AS FIleName
FROM
dbo.OperatingSystemInstallFiles oi
JOIN dbo.InstallFileTypes i ON oi.InstallFileTypeId = i.InstallFileTypeId
JOIN dbo.OperatingSystems o ON oi.OperatingSystemId = o.OperatingSystemId
You've put a SELECT inside another SELECT list without nesting, which is a syntax error in SQL Server.
You are also attempting to assign a variable while performing a data-retrieval operation. You can select all data to be shown, or all data into variables but not both at the same time.
When the two issues above are resolved, I think you may still run into issues when committing filenames into a variable which only allows 20 characters - but then I don't know anything about your dataset.

Condition WHERE clauses inside stored procedure

I am working with a stored procedure where I want to add or remove WHERE clauses according to the values of a couple parameters.
This is what I've got so far:
WHERE
t.iDdPais = #iIdPais
AND t.iIdRegion = #iIdRegion
AND t.dtFecha BETWEEN #dtStart AND #dtEnd
BUT, if #iIdPais is 0 (which means ALL), I need to remove that clause from the WHERE statement, the same goes to #iIdRegion.
Put the entire SELECT inside IF clause..
IF(#ildPais =0 AND #ildRegion =0)
SELECT <THE DATASET> FROM THE TABLE
WHERE
t.iDdPais = #iIdPais
AND t.iIdRegion = #iIdRegion
AND t.dtFecha BETWEEN #dtStart AND #dtEnd
ELSE
SELECT <THE DATASET> FROM THE TABLE
--no where clause
You just need to use normal boolean logic:
WHERE
(#iIdPaid = 0 OR t.iDdPais = #iIdPais)
AND (#iIdRegion=0 OR t.iIdRegion = #iIdRegion)
AND t.dtFecha BETWEEN #dtStart AND #dtEnd

T-SQL Procedure not working, issue with varchar to date conversion

When I run this SP, I get:
Msg 241, Level 16, State 1, Procedure PED_SP_PED_Updates, Line 22
Conversion failed when converting date and/or time from character string.
Here is the execution:
exec dbo.ped_sp_ped_updates
#CURRENTHICN='111111111A',
#DATERECEIVED = '20140904',
#FIELDTOBECHANGED='FIRST_NAME_MEMBER',
#CURRENTFIELDVALUE = 'MARY',
#NEWFIELDVALUE = 'MARYTEST',
#REQUESTEDBY = 'IPISORS',
#ID=156
I am not sure why, I'm casting the varchar back to a date for the comparison.
Please note, I have no problem being told a better way to do it, but it would be (I think) more helpful to my learning if I could, at least 'also', get a direct answer as to why my current proc isn't working. In addition to any helpful ideas as to why it should be done different, better, etc, etc. etc.
ALTER PROCEDURE [dbo].[PED_SP_PED_Updates]
#CurrentHicn VARCHAR(500),
#DateReceived VARCHAR(20),
#FieldToBeChanged VARCHAR(500),
#CurrentFieldValue VARCHAR(500),
#NewFieldValue VARCHAR (500),
#RequestedBy VARCHAR(10),
#ID int
AS
BEGIN
-- SET NOCOUNT ON added to prevent extra result sets from
-- interfering with SELECT statements.
SET NOCOUNT ON;
-- Insert statements for procedure here
DECLARE #CurrentDBNote VARCHAR(MAX)
DECLARE #NewNote VARCHAR(MAX)
DECLARE #CountofHicn INT
SET #NEWNOTE = 'Isaac Pisors | ' + GetDate() + ' | '
+ 'Changing field: ' + #FieldToBeChanged + ' from ' + #CurrentFieldValue + ' to ' + #NewFieldValue
+ ', per ' + #RequestedBy + ' request. Also changing any related DOCS/FAXES records to correspond'
SET #CurrentDBNote=
(SELECT NOTES_GENERAL FROM PED_APPLICATIONS WHERE HICN_MEDICARE_NUMBER=#CurrentHicn AND (Cast(ISNULL(DATE_RECEIVED,'1900-01-01') as DATE)=CAST(#DateReceived AS DATE)))
--NOW ADD THE TWO:
SET #NewNote = #CurrentDBNote + CHAR(13) + #CurrentDBNote
--SEE IF THERE IS STILL A MATCHING RECORD
SET #CountofHicn=
(SELECT COUNT(*) FROM PED_APPLICATIONS WHERE HICN_MEDICARE_NUMBER=#CurrentHicn AND (CAST(ISNULL(DATE_RECEIVED,'1900-01-01') AS DATE)=CAST(#DateReceived AS DATE)))
IF #CountofHicn=0 --THERE IS NO LONGER A MATCHING RECORD - INSERT THAT NOTE AND CALL IT A DAY
BEGIN
UPDATE PED_PEDUPDATES SET COMPLETEDON=GetDate(), COMPLETEDBY='SSIS',
EXCEPTIONNOTE='Could not locate any records where HICN is ' + #CurrentHicn + ' and Date Received is ' + CAST(#DateReceived AS VARCHAR)
WHERE [ID]=#ID
END
ELSE --GO AHEAD AND DO THE UPDATE
BEGIN
UPDATE PED_APPLICATIONS SET #FieldToBeChanged = #NewFieldValue
WHERE HICN_MEDICARE_NUMBER=#CurrentHicn AND (CAST(ISNULL(DATE_RECEIVED,'1900-01-01') AS DATE)=CAST(#DateReceived AS DATE))
END
IF #FieldToBeChanged='HICN_MEDICARE_NUMBER' --THEN WE HAVE TO UPDATE DOCS TABLE, TOO
BEGIN
UPDATE PED_DOCS SET HICN_MEDICARE_NUMBER=#NewFieldValue
WHERE
(HICN_MEDICARE_NUMBER=#CurrentFieldValue AND (CAST(ISNULL(DATE_RECEIVED,'1900-01-01') AS DATE)=#DateReceived)) or
(HICN_MEDICARE_NUMBER=#CurrentFieldValue AND DATE_RECEIVED IS NULL)
END
IF #FieldToBeChanged='HICN_MEDICARE_NUMBER' --THEN OUR WHERE CLAUSE-HICN IS THE *NEW* HICN
BEGIN
UPDATE PED_APPLICATIONS SET NOTES_GENERAL=#NewNote
WHERE HICN_MEDICARE_NUMBER=#NewFieldValue AND (CAST(ISNULL(DATE_RECEIVED,'1900-01-01') AS DATE)=CAST(#DateReceived AS DATE))
END
ELSE --ELSE OUR WHERE CLAUSE-HICN IS THE *OLD* HICN
BEGIN
UPDATE PED_APPLICATIONS SET NOTES_GENERAL=#NewNote
WHERE HICN_MEDICARE_NUMBER=#CurrentHicn AND (CAST(ISNULL(DATE_RECEIVED,'1900-01-01') AS DATE)=CAST(#DateReceived AS DATE))
END
--FINALLY, UPDATE RECORD AS COMPLETE:
UPDATE PED_PEDUPDATES SET COMPLETEDON=GetDate(),COMPLETEDBY='SSIS' WHERE [ID]=#ID
END
GO
Short Term Fix
Instead of CAST(#DateReceived AS DATE), use CONVERT(date, #DateReceived, 112)
The value 112 is the style code for the yyyymmdd formated varchar you're using. See the cast and convert documentation for more details.
Also, you should verify that all values in the DATE_RECEIVED column of your table are in the correct format. Even one value that is not convertible will cause this error.
Proper Fix
#DateReceived should be passed in to the procedure as a date instead of a varchar.
The DATE_RECEIVED field in your table should be declared as a date instead of a varchar.
In general, avoid treating dates or times as strings in a database when there are native types for that purpose.

Need help joining 3rd table to Stored Proc

I have a stored Procedure that works fine joining 2 tables together. I needed to add a new field from a new table that was not included in the original SP. What I am trying to do is sum a field from the new table for each record that is a child record of the Parent table which is in the original SP.
I tested the Sum based on th parent table in a test query and it works fine:
select totaldollars from TTS_EmpTime where emptimedaytotal_id='32878'
so then the next step would be to integrate into the SP. I did so and have set the new portions of the SP to be bold so you can see what was added. IF the bold portions are removed the SP works fine if not I get this error:
*Msg 8120, Level 16, State 1, Procedure TTS_RptTest2, Line 11
Column 'TTS_EmpTimeDayTotal.EmployeeID' is invalid in the select list because it is not contained in either an aggregate function or the GROUP BY clause*.
Here is my Stored Proc:
USE [TTSTimeClock]
GO
/****** Object: StoredProcedure [dbo].[TTS_RptTest2] Script Date: 03/04/2011 12:29:59 ******/
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
ALTER procedure [dbo].[TTS_RptTest2]
#BureauID nvarchar(36),
#CompanyID nvarchar(36),
#DivisionID nvarchar(10) ,
#punchDate smalldatetime,
#PeriodDays integer,
#EmployeeID nvarchar(20) = null
As
--with DayTotals as(
select
DayTotal.DivisionID,
DayTotal.EmployeeID,
EmpData.EmployeeFirstName AS First,
EmpData.EmployeeLastName AS Last,
EmpData.employeetypeid AS EmpId,
DayTotal.ID as DayTotalID,
-- Format the Date as MM/DD DOW or 2Digit Month & 2Digit Day and the 3Char Day of the week Uppercase
convert(varchar(5),DayTotal.PunchDate,101) + ' ' + upper(left(datename(dw,DayTotal.Punchdate),3))as PunchDate,
-- Format the in and out time as non military time with AM or PM No Dates
substring(convert(varchar(20), DayTotal.FirstDayPunch, 9), 13, 5) + ' ' + substring(convert(varchar(30), DayTotal.FirstDayPunch, 9), 25, 2)as TimeIn,
substring(convert(varchar(20), DayTotal.LastDayPunch, 9), 13, 5) + ' ' + substring(convert(varchar(30), DayTotal.LastDayPunch, 9), 25, 2) as TimeOut,
DayTotal.RegularHours,
DayTotal.NonOvertimeHours,
DayTotal.OvertimeHours,
DayTotal.TotalDayHRS,
DayTotal.PeriodRegular,
DayTotal.PeriodOtherTime,
DayTotal.PeriodOvertime,
DayTotal.PeriodTotal,
**sum(cast(EmpTime.TotalDollars as float)) as TotalDayDollars**
from TTS_EmpTimeDayTotal as DayTotal
INNER JOIN TTS_PayrollEmployees AS EmpData
ON DayTotal.EmployeeID = EmpData.EmployeeID
**inner JOIN TTS_Emptime as EmpTime
ON DayTotal.id = emptime.emptimedaytotal_id**
where
DayTotal.BureauID = #BureauID
AND DayTotal.CompanyID = #CompanyID
AND (DayTotal.DivisionID = #DivisionID)
AND daytotal.periodstart =
-- Period start date
(SELECT DISTINCT PeriodStart
FROM TTS_EmpTimeDayTotal
WHERE(BureauID = #BureauID) AND (CompanyID = #CompanyID) AND ( (DivisionID = #DivisionID))
AND (PunchDate = #punchDate)and periodend = dateadd(d,(#PeriodDays - 1),(periodstart)))
AND daytotal.periodend =
-- Period End Date
(SELECT DISTINCT PeriodEnd
FROM TTS_EmpTimeDayTotal
WHERE(BureauID = #BureauID) AND (CompanyID = #CompanyID) AND ( (DivisionID = #DivisionID))
AND (PunchDate = #punchDate)and periodend = dateadd(d,(#PeriodDays-1),(periodstart)))
-- Optional all employees or just one
AND (( #EmployeeID is Null) or (DayTotal.EmployeeID = #EmployeeID))
order by Empdata.employeetypeid,DayTotal.punchdate
I am not grouping at all so this must be caused by something else?
Any Help will be appreciated
Is this SQL Server? Looks like it. You're using SUM, an aggregate function, which I don't believe you can use without a GROUP BY clause. Did you always have the SUM in there, or did you add it alongside the new table?
If the latter, that may well be your problem.
Update
Based on OP's comment:
Wow that could be a pain would I do
somehing like groupby field1,field2,
and so on? as in a coma delimited
list. Is there another way to include
this one field that would be better?
Yes, in SQL Server you must be explicit with groupings when using an aggregate function. One alternative in your case would be to do the grouping as a subquery, and join on that, i.e.:
FROM TTS_EmpTimeDayTotal AS DayTotal
INNER JOIN TTS_PayrollEmployees AS EmpData ON DayTotal.EmployeeID = EmpData.EmployeeID
INNER JOIN (SELECT EmpTimeDayTotal_id, SUM(CAST(TotalDollars AS FLOAT)) AS TotalDayDollars
FROM TTS_Emptime
GROUP BY EmpTimeDayTotal_id) AS EmpTime ON DayTotal.id = EmpTime.EmpTimeDayTotal_id
And then simply reference EmpTime.TotalDayDollars in the SELECT list, instead of performing the SUM there.