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.
Related
First, I have read about similar posts and have read the comments that this isn't an ideal solution and I get it but the boss (ie client) wants it this way. The parameters are as follows (for various reasons too bizarre to go into but trust me):
1. SQL Server Mgmt Studio 2016
2. NO parameters or pass throughs or temp tables. All has to be within contained code.
So here we go:
I need to create column headings that reflect dates:
1. Current date
2. Most recent quarter end prior to current date
3. Most recent quarter end prior to #2
4. Most recent quarter end prior to #3
5. Most recent quarter end prior to #4
6. Most recent quarter end prior to #5
So if using today's date, my column names would be as follows
12/18/2016 9/30/2016 6/30/2016 3/31/2016 12/31/2016 9/30/2015
I can easily do it in SAS but can't in SQL given the requirements stated above.
Help please with same code.
Thank you
Paula
Seems like a long way to go for something which really belongs in the presentation layer. That said, consider the following:
Let's assume you maintain a naming convention for your calculated fields, for example [CurrentDay], [QtrMinus1], [QtrMinus2], [QtrMinus3], [QtrMinus4],[QtrMinus5]. Then we can wrap your complicated query in some dynamic SQL.
Just as an illustration, let's assume your current query results looks like this
After the "wrap", the results will then look like so:
The code - Since you did NOT exclude Dynamic SQL.
Declare #S varchar(max)='
Select [CustName]
,['+convert(varchar(10),GetDate(),101)+'] = [CurrentDay]
,['+Convert(varchar(10),EOMonth(DateFromParts(Year(DateAdd(QQ,-1,GetDate())),DatePart(QQ,DateAdd(QQ,-1,GetDate()))*3,1)),101)+'] = [QtrMinus1]
,['+Convert(varchar(10),EOMonth(DateFromParts(Year(DateAdd(QQ,-2,GetDate())),DatePart(QQ,DateAdd(QQ,-2,GetDate()))*3,1)),101)+'] = [QtrMinus2]
,['+Convert(varchar(10),EOMonth(DateFromParts(Year(DateAdd(QQ,-3,GetDate())),DatePart(QQ,DateAdd(QQ,-3,GetDate()))*3,1)),101)+'] = [QtrMinus3]
,['+Convert(varchar(10),EOMonth(DateFromParts(Year(DateAdd(QQ,-4,GetDate())),DatePart(QQ,DateAdd(QQ,-4,GetDate()))*3,1)),101)+'] = [QtrMinus4]
,['+Convert(varchar(10),EOMonth(DateFromParts(Year(DateAdd(QQ,-5,GetDate())),DatePart(QQ,DateAdd(QQ,-5,GetDate()))*3,1)),101)+'] = [QtrMinus5]
From (
-- Your Complicated Query --
Select * from YourTable
) A
'
Exec(#S)
If it helps the visualization, the generated SQL is as follows:
Select [CustName]
,[12/18/2016] = [CurrentDay]
,[09/30/2016] = [QtrMinus1]
,[06/30/2016] = [QtrMinus2]
,[03/31/2016] = [QtrMinus3]
,[12/31/2015] = [QtrMinus4]
,[09/30/2015] = [QtrMinus5]
From (
-- Your Complicated Query --
Select * from YourTable
) A
Here is one way using dynamic query
DECLARE #prior_quarters INT = 4,
#int INT =1,
#col_list VARCHAR(max)=Quotename(CONVERT(VARCHAR(20), Getdate(), 101))
WHILE #int <= #prior_quarters
BEGIN
SELECT #col_list += Concat(',', Quotename(CONVERT(VARCHAR(20), Eomonth(Getdate(), ( ( ( ( Month(Getdate()) - 1 ) % 3 ) + 1 ) * -1 ) * #int), 101)))
SET #int+=1
END
--SELECT #col_list -- for debugging
EXEC ('select '+#col_list+' from yourtable')
Context
We are currently in the process of cleaning up an SQL database and we've come across a large amount of Stored Procedures which only have slight differences between them. We wish to consolidate them into a single proc to allow for easier maintenance.
Problem
Below are just two examples of the kind of stored procs we're attempting to merge (do note, these are simplified versions, not the actual procs).
Stored Procedure - Current Bookings
ALTER PROCEDURE [dbo].[SelectCurrentBookings]
#client_FK INT, #startDate DATETIME, #endDate DATETIME
AS
BEGIN
SELECT ROW_NUMBER() OVER (ORDER BY [Booking].[bookingDateTime]) [RowNumber],
[Booking].[booking_PK] [Booking ID],
[Booking].[bookingDateTime] [Booking Date],
[Booking].[bookingDuration] [Duration],
[Booking].[client] [Client Name],
CASE WHEN [Booking].[bookingStatusCode_FK] IN (4,8,9,7,16) THEN 1 ELSE 0 END [Unserviced],
FROM [Booking]
WHERE [client_FK] = #client_FK
AND [Booking].[bookingStatusCode_FK] IN (1,2,14,17)
AND [Booking].[bookingDateTime] >= #startDate
AND [Booking].[bookingDateTime] < DATEADD(d,1,#endDate)
AND [Booking].[deleted] = 0
END
Stored Procedure - Archived Bookings
ALTER PROCEDURE [dbo].[SelectArchivedBookings]
#client_FK INT, #startDate DATETIME, #endDate DATETIME
AS
BEGIN
SELECT ROW_NUMBER() OVER (ORDER BY [Booking].[bookingDateTime]) [RowNumber],
[Booking].[booking_PK] [Booking ID],
[Booking].[bookingDateTime] [Booking Date],
[Booking].[bookingDuration] [Duration],
[Booking].[client] [Client Name],
CASE WHEN [Booking].[bookingStatusCode_FK] IN (4,8,9,7,16) THEN 1 ELSE 0 END [Unserviced],
FROM [Booking]
WHERE [client_FK] = #client_FK
AND [Booking].[bookingStatusCode_FK] IN (1,2,14,4,9,7,16,13)
AND [Booking].[bookingDateTime] >= #startDate
AND [Booking].[bookingDateTime] < DATEADD(d,1,#endDate)
AND [Booking].[deleted] = 0
END
The code which invokes the stored procs is in VB.NET
Dim Command As DbCommand = _db.GetStoredProcCommand("SelectCurrentBookings")
_db.AddInParameter(Command, "client_FK", DbType.Int32, ClientID)
_db.AddInParameter(Command, "startDate", DbType.DateTime, StartDate)
_db.AddInParameter(Command, "endDate", DbType.DateTime, EndDate)
Return _db.ExecuteDataSet(Command)
As you can see, the only difference between the above stored procs are the values supplied to the WHERE IN.
Is there a way for us to modify this and have the list of values supplied through a parameter or variable?
If the objective is to reduce maintenance effort I would humbly suggest that moving data values out of the data layer and hard-coding them in the logic layer, perhaps in several places, is maybe not contributing to this objective.
Removing these explicit values from the queries will remove information the optimiser can use to create a plan. Be careful you replace it with something better else query performance may suffer. I would posit these SPs are separated precisely so unique plans exist for each, especially if the queries are much more complex than is shown. Compare the current plans against each other and whatever you end up with to ensure you haven't regressed.
One option may be to create a new "list" table:
ListName StatusCode
current 1
current 2
...
current 17
archive 1
archive 2
archive 4
...
archive 16
Join to this table instead of using an IN clause. Qualify the join by ListName, which is passed as a parameter. A unique clustered index on (ListName, StatusCode) would be good. You may consider creating a filtered statistic for each ListName. Create a foreign key constraint if you hold a master list of status values.
The stored procedure then becomes
ALTER PROCEDURE [dbo].[SelectCurrentBookings]
#client_FK INT, #startDate DATETIME, #endDate DATETIME,
#ListName char(10)
AS
BEGIN
SELECT ROW_NUMBER() OVER (ORDER BY [Booking].[bookingDateTime]) [RowNumber],
...
FROM [Booking]
INNER JOIN dbo.List as l
ON [Booking].[bookingStatusCode_FK] = l.StatusCode
AND l.ListName = #ListName
WHERE [client_FK] = #client_FK
AND [Booking].[bookingDateTime] >= #startDate
AND [Booking].[bookingDateTime] < DATEADD(d,1,#endDate)
AND [Booking].[deleted] = 0
END
The calling code gains a parameter
Dim Command As DbCommand = _db.GetStoredProcCommand("SelectCurrentBookings")
_db.AddInParameter(Command, "client_FK", DbType.Int32, ClientID)
_db.AddInParameter(Command, "startDate", DbType.DateTime, StartDate)
_db.AddInParameter(Command, "endDate", DbType.DateTime, EndDate)
_db.AddInParameter(Command, "ListName", DbType.String, "current") //correct type needed
Return _db.ExecuteDataSet(Command)
This way meanings for status codes are recorded in one place and good statistics are available to the optimiser. Whether this is faster than the current implementation, only testing can tell.
"We wish to consolidate them into a single proc to allow for easier maintenance."
I would agree, having multiple stored procedure's that do the same thing except a certain condition can be maintenance hell; especially if these are all over the place. Below I have a few different options and or solutions you could try out. With this in mind, I will let you decide how you would like to approach this as each option is different as in execution plans etc.
"the only difference between the above stored procs are the values supplied to the WHERE IN"
Option One
Create a system table for example: dbo.System_Booking_Status. This table would only need a few columns: System_Status_ID (Primary Key),Booking_Status_Code INT NOT NULL and Booking_Status BIT NOT NULL
Now you can populate this table with your values. The booking status column could mean 1 for current and 2 for archive; however you wish. Or make it a VarChar(15) type and use a description (Current or Archived) so it is distinguished OR a Char(1) type and use (C - for current & A - for archive).
Now that you have a system table you can join to we need to tell the stored procedure to do so and when. I used a new parameter called: status which would need to be passed in when you make the call to either get the current and or archived records back.
ALTER PROCEDURE [dbo].[SelectCurrentBookings]
#client_FK INT, #startDate DATETIME, #endDate DATETIME, #status INT
AS
BEGIN
IF #status = 1 --current
BEGIN
SELECT ROW_NUMBER() OVER (ORDER BY b.[bookingDateTime]) [RowNumber],
b.[booking_PK] [Booking ID],
b.[bookingDateTime] [Booking Date],
b.[bookingDuration] [Duration],
b.[client] [Client Name],
CASE WHEN b.[bookingStatusCode_FK] IN (4,8,9,7,16) THEN 1 ELSE 0 END [Unserviced],
FROM [Booking] b
INNER JOIN dbo.System_Booking_Status sbs
ON sbs.Booking_Status_Code = b.bookingStatusCode_FK
AND sbs.Booking_Status = 1 --current?
WHERE [client_FK] = #client_FK
AND b.[bookingDateTime] >= #startDate
AND b.[bookingDateTime] < DATEADD(d,1,#endDate)
AND b.[deleted] = 0
END
ELSE
BEGIN
SELECT ROW_NUMBER() OVER (ORDER BY b.[bookingDateTime]) [RowNumber],
b.[booking_PK] [Booking ID],
b.[bookingDateTime] [Booking Date],
b.[bookingDuration] [Duration],
b.[client] [Client Name],
CASE WHEN b.[bookingStatusCode_FK] IN (4,8,9,7,16) THEN 1 ELSE 0 END [Unserviced],
FROM [Booking] b
INNER JOIN dbo.System_Booking_Status sbs
ON sbs.Booking_Status_Code = b.bookingStatusCode_FK
AND sbs.Booking_Status = 2 --archived?
WHERE [client_FK] = #client_FK
AND b.[bookingDateTime] >= #startDate
AND b.[bookingDateTime] < DATEADD(d,1,#endDate)
AND b.[deleted] = 0
END
END
Now you do not have to use hard coded values and eliminate the IN clause by using the INNER JOIN.
Option Two (Quick n Dirty)
Pass in another variable to either determine if you want current or archived records back.
IF #status = 1....
BEGIN
--Normal query executed for active...
END
ELSE
BEGIN
--Normal query executed for archived...
END
Option Three
You can pass in XML of the values that you would need. Parse this XML out into a Table Variable and then join to this. It would eliminate your IN clause and better execution plan as well.
For example:
Declare #Status_Codes XML = ''
DECLARE #StatusTable TABLE
(
Status_Code INT
)
-- Parse the XML in to the temp table declared above
INSERT INTO #StatusTable(Status_Code)
SELECT
xmlData.A.value('.', 'INT')
FROM #Status_Codes.nodes('BookingStatus/StatusCode/Code') xmlData(A)
Now you have a Table Variable you can join to...
FROM [Booking] b
INNER JOIN #StatusTable s
ON s.Status_Code = b.bookingStatusCode_FK
Next you have to pass this data in from your function call. You can create a function that would return the formatted XML and pass that into your stored procedure call.
Public Shared Function ConstructXMLStatusCodes(ByVal intStatus As Integer) As String
Dim strBuilder As New System.Text.StringBuilder
If intStatus = 1 'active...
With strBuilder
.AppendLine("<BookingStatus>")
.AppendLine("<StatusCode>")
.AppendLine("<Code>1</Code>")
.AppendLine("<Code>2</Code>")
'continue to add more codes...
.AppendLine("</StatusCode>")
.AppendLine("</BookingStatus>")
End With
Else
'Create your builder with the archive...
End If
Return strBuilder.ToString()
End Function
Then make your call before passing it to your function OR make the call in your function; you have more than a few choices...
On another Note
I notice you are executing a DataSet but you are never returning one, I would use the DataTable.Load method that executes a reader and fills a table...
Good Luck!
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.
I am adding records into my table "SampleTestLimits" using an "Insert Into Select", but which also has a sub-query reading from the same table to perform a count for me.
I don't think the sub-query is seeing the earlier records added by my "Insert Into Select". It's the same for Oracle and SQL Server. The code for SQL Server is shown below (my sub-query begins with "SELECT COALESCE...").
I have another stored procedure which does work in a similar situation.
Would appreciate it if anybody could tell if what I'm doing is a no no.
ALTER PROCEDURE [dbo].[CreateSampleTestLimits]
#SampleCode as NVARCHAR(80),
#TestPosition as smallint,
#TestCode NVARCHAR(20),
#TestVersion smallint,
#EnterDate as integer,
#EnterTime as smallint,
#EnterUser as NVARCHAR(50)
AS
BEGIN
INSERT INTO SampleTestLimits
([AuditNumber]
,[LimitNumber]
,[ComponentRow]
,[ComponentColumn]
,[ComponentName]
,[TestPosition]
,[SampleCode]
,[AuditFlag]
,[LimitSource]
,[LimitType]
,[UpperLimitEntered]
,[UpperLimitValue]
,[LowerLimitEntered]
,[LowerLimitValue]
,[LimitTextColour]
,[LimitPattern]
,[LimitForeColour]
,[LimitBackColour]
,[CreatedDate]
,[CreatedTime]
,[CreatedUser]
,[LimitText]
,[FilterName]
,[deleted]
,IsRuleBased)
SELECT 1 --starting auditnumber
,(SELECT COALESCE(MAX(LimitNumber), 0) + 1 AS NextLimitNumber FROM SampleTestLimits WHERE SampleCode=#SampleCode AND TestPosition=#TestPosition AND ComponentRow=1 AND ComponentColumn=1 AND AuditFlag=0) -- TFS bug# 3952: Calculate next limit number.
,ComponentRow
,ComponentColumn
,(select ComponentName from TestComponents TC where TC.TestCode=#TestCode and TC.ComponentColumn=TestLimits.ComponentColumn and TC.ComponentRow = TestLimits.ComponentRow and TC.AuditNumber=TestLimits.AuditNumber)
,#TestPosition
,#SampleCode
,0 --auditflag
,1 --limitsource = test
,[LimitType]
,[UpperLimitEntered]
,[UpperLimitValue]
,[LowerLimitEntered]
,[LowerLimitValue]
,[LimitTextColour]
,[LimitPattern]
,[LimitForeColour]
,[LimitBackColour]
,#EnterDate
,#EnterTime
,#EnterUser
,[LimitText]
,[FilterName]
,0 --deleted
,0 --rule based
FROM TestLimits join Tests on Tests.TestCode=TestLimits.TestCode and Tests.AuditNumber= TestLimits.AuditNumber WHERE Tests.TestCode=#TestCode and Tests.auditnumber=#TestVersion and ([TestLimits].FilterString is null or DATALENGTH([TestLimits].FilterString)=0)
END
Assuming that I understand your logic correctly (ie. that you want the nextlimitnumber to increase by 1 for each row being added), in Oracle, I'd do it by using the analytic function row_number() to work out what number to add to the previous max value, something like:
INSERT INTO sampletestlimits (auditnumber,
limitnumber,
componentrow,
componentcolumn,
componentname,
testposition,
samplecode,
auditflag,
limitsource,
limittype,
upperlimitentered,
upperlimitvalue,
lowerlimitentered,
lowerlimitvalue,
limittextcolour,
limitpattern,
limitforecolour,
limitbackcolour,
createddate,
createdtime,
createduser,
limittext,
filtername,
deleted,
isrulebased)
SELECT 1, --starting auditnumber
(SELECT COALESCE (MAX (limitnumber), 0) + 1 AS nextlimitnumber
FROM sampletestlimits
WHERE samplecode = p_samplecode
AND testposition = p_testposition
AND componentrow = 1
AND componentcolumn = 1
AND auditflag = 0)
+ row_number() over (partition by testposition, componentrow, componentcolumn, auditflag) as nextlimitnumber, -- TFS bug# 3952: Calculate next limit number.
componentrow,
componentcolumn,
(SELECT componentname
FROM testcomponents tc
WHERE tc.testcode = p_testcode
AND tc.componentcolumn = testlimits.componentcolumn
AND tc.componentrow = testlimits.componentrow
AND tc.auditnumber = testlimits.auditnumber),
p_testposition,
p_samplecode,
0, --auditflag
1, --limitsource = test
limittype,
upperlimitentered,
upperlimitvalue,
lowerlimitentered,
lowerlimitvalue,
limittextcolour,
limitpattern,
limitforecolour,
limitbackcolour,
p_enterdate,
p_entertime,
p_enteruser,
limittext,
filtername,
0, --deleted
0 --rule based
FROM testlimits
JOIN tests
ON tests.testcode = testlimits.testcode
AND tests.auditnumber = testlimits.auditnumber
WHERE tests.testcode = p_testcode
AND tests.auditnumber = p_testversion
AND ( testlimits.filterstring IS NULL
OR datalength (testlimits.filterstring) = 0);
I had to guess at what the partition by clause would need to contain - adjust that as necessary for your requirements.
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!)