1

I have this sql stored procedure which is supposed to look at a particular table and return job numbers based on a date column. This works great except for when its run Saturday morning (and should return all job numbers with a date of Friday, but returns no rows). Any suggestions? Is there some logic problem here I'm not seeing? How might I track this down?

Stored Procedure

ALTER Procedure [dbo].[JC_GetJobsClosedYesterday]

As

SELECT [JobNumber]
  FROM [NCLGS].[dbo].[JobClosedDate]
  Where LastInvoiceDate between dbo.ufn_StartOfDay (DATEADD(d, -1, GETDATE())) AND dbo.ufn_StartOfDay (GETDATE())
  order by JobNumber desc

And the start of day function.

ALTER function [dbo].[ufn_StartOfDay] ( @inDate datetime )

RETURNS DateTime AS 
BEGIN   
DECLARE @Now datetime   
set @Now = @inDate
DECLARE @DayStart datetime
set @DayStart = @Now

set @DayStart = DATEADD (ms, -DATEPART(ms,@Now),@DayStart)
set @DayStart = DATEADD (s, -DATEPART(s,@Now),@DayStart)
set @DayStart = DATEADD (mi, -DATEPART(mi,@Now),@DayStart)
set @DayStart = DATEADD (hh, -DATEPART(hh,@Now),@DayStart)

return @DayStart 
END

EDIT: I'm not having trouble with my date conversion (unless it doesn't know how to handle Fridays). I need help with the returning no rows part.

SAMPLE DATA:

JobNumber   LastInvoiceDate             DayOfWeek
112117      2011-06-13 00:00:00.000     Monday
112089      2011-06-10 00:00:00.000     Friday
112090      2011-06-10 00:00:00.000     Friday
112068      2011-06-10 00:00:00.000     Friday
112082      2011-06-10 00:00:00.000     Friday

UPDATE: Now I'm really confused. This "no data on fridays" thing has been happening (happened again last friday), but I still can't figure it out. Is it possible that GETDATE() isn't returning what I think its returning? Because when I try the following modifications based on @Thomas's suggestion, both methods get data, but the report that generated based on this code last sat has no data.

DECLARE @date datetime
--SET @date = '2011-06-21 13:42:27.257'
SET @date = '2011-06-11 03:42:27.257'

--Original Code
SELECT [JobNumber]
  FROM [NCLGS].[dbo].[JobClosedDate]
  Where LastInvoiceDate between dbo.ufn_StartOfDay (DATEADD(d, -1, @date)) AND dbo.ufn_StartOfDay (@date)
  order by JobNumber desc

  --Returns 21 records

--Modified based on @Thomas suggestion
Select [JobNumber]
From [NCLGS].[dbo].[JobClosedDate]
Where LastInvoiceDate >= DateAdd( d, DateDiff( d, 0, @date ) - 1, 0 )
    And LastInvoiceDate < DateAdd( d, DateDiff( d, 0, @date ), 0 )
Order By JobNumber Desc

  --Returns 21 records
MAW74656
  • 3,449
  • 21
  • 71
  • 118
  • Why can't you use CONVERT(varchar,getdate(),101) – THEn Jun 14 '11 at 17:48
  • @THEn -No reason. This is code I've inherited. – MAW74656 Jun 14 '11 at 17:50
  • 1
    Dow you have sample data at least 1 row that is not showing.... – THEn Jun 14 '11 at 17:55
  • @MAW74656, performance aside, the only logic problem I see is the fact that `between` is inclusive of both endpoints. Based on your sample data, what didn't work? (i.e. when was the query ran, what did it return, and what should it have returned?) – chezy525 Jun 21 '11 at 17:37
  • @MAW74656 - Is it that it is not pulling down data *for last Friday* or *on last Friday* or *on last Saturday*? The former would imply that the routine ran on Saturday for Friday's data. The later two would imply something might have hiccuped in the running of the routine itself instead of the query. – Thomas Jun 21 '11 at 19:08
  • On any given day, the report is run and should have data from the previous day. Today is 6/21, so report ran today should have jobnumbers from 6/20. – MAW74656 Jun 21 '11 at 19:11
  • @MAW74656 - It should also be noted that it is a coincidence of the data that you happened to get the same results in the last two queries you posted. The first of the two queries will return all invoices dated from the previous day at midnight through *and including* the current date at midnight. Thus, for the current date of `2011-06-11`, if there was an invoice dated `2011-06-11`, it would show in the first query and not in the second. – Thomas Jun 21 '11 at 19:13
  • @Thomas -Ok, I understand your point. I can experiment with that. However, both queries clearly return > 0 records when ran right now. Why would that be different at 3am on Saturday morning? Also, I'm not concerned because invoices are almost never made outside of 7am-5pm. – MAW74656 Jun 21 '11 at 19:17
  • @MAW74656 - Does the actual query include any other criteria such as a state of the invoice (e.g. posted, not posted etc) that would exclude rows? – Thomas Jun 21 '11 at 19:18
  • @MAW74656 - Are you sure that the job is executed on Saturday morning? It could be configured to run weekly at 03:00 on the days mon,tue,wed,thu,fri. – Mikael Eriksson Jun 21 '11 at 19:25
  • @Thomas -No, just the invoicedate. Jobs are not added into this table until they meet certain criteria, so there is no need to filter for them. – MAW74656 Jun 21 '11 at 19:28
  • @Mikael Eriksson -The stored procedure is used by a C#.Net console program to generate a detailed PDF report about each job that is then attached to an email. I get an email on saturday mornings that always has 0 job reports attached. So I am sure its running on Saturday. – MAW74656 Jun 21 '11 at 19:29
  • @MAW74656 - How does the last invoice date get updated? Is there another job that does that? – Thomas Jun 21 '11 at 20:37
  • @Thomas -Yes, but I don't see any connection to this problem. When someone invoices a job that job is set to closed and a record is inserted into this table. – MAW74656 Jun 21 '11 at 20:47
  • @MAW74656 - The reason I ask is to determine whether the LastInvoiceDate is getting updated after the automated job that queries your table. If you are able to run the query now with current date of Sat and it gives you results, then that limits the possible reasons why you wouldn't get data: 1. either the rows do not exist at the time you run the query (remember to account for rows in joined tables too). 2. the last invoice date values are different at the time the query is run vs now. – Thomas Jun 21 '11 at 21:21
  • @Thomas -Yes, I see what could be happening. I need to find out when this table is populated. How can I get snapshots of a table automatically? I guess I need to see whats in the table before, during and after this procedure is scheduled. What else can I do? – MAW74656 Jun 22 '11 at 15:27
  • @MAW74656 - One simple solution would be to adjust the automated job to email you a result count a multiple intervals. E.g., at 5 PM Fri, 7 PM Fri, 11 PM Fri, 1 AM Sat and 3 AM Sat. Theoretically, the results should be the same across all queries. If they are different, it means the data is changing during one of the intervals. – Thomas Jun 22 '11 at 16:13

3 Answers3

5

Instead of DATEADD(d, -1, GETDATE()) you should use an expression that returns the beginning of the previous day. You could use your dbo.ufn_StartOfDay() function for that, but there's simpler way to do the same:

Select @DayStart = DateAdd( d, DateDiff( d, 0, @inDate ), 0 )

which means: increase the nil timestamp by the whole number of days between the nil timestamp and the given one.

I would also suggest using that expression instead of the already present call to the function as well, so your query would be:

Select [JobNumber]
From [NCLGS].[dbo].[JobClosedDate]
Where LastInvoiceDate Between DateAdd( d, DateDiff( d, 0, GetDate() ) - 1, 0 )
                          And DateAdd( d, DateDiff( d, 0, GetDate() ),     0 )
Order By JobNumber Desc

Addition

You need to be clearer about where exactly the problem is. Here is a sample query I created which tests every date from Thursday, June 9 through Saturday June 18. On which date did you expect to get values but did not or visa versa:

With SampleData As
    (
    Select 112117 As JobNumber, '2011-06-13 00:00:00.000' As LastInvoiceDate, 'Monday' As DayOfWeek
    Union All Select 112089, '2011-06-10 00:00:00.000', 'Friday'
    Union All Select 112090, '2011-06-10 00:00:00.000', 'Friday'
    Union All Select 112068, '2011-06-10 00:00:00.000', 'Friday'
    Union All Select 112082, '2011-06-10 00:00:00.000', 'Friday'
    )
    , TestDates As
    (
    Select Cast('20110609' As datetime) As Date
    Union All
    Select DateAdd(d,1,Date)
    From TestDates
    Where Date <= '20110617'
    )
Select TD.Date, DateName(dw,TD.Date), Count(SD.JobNumber)
From TestDates As TD
    Left Join SampleData As SD
        On SD.LastInvoiceDate Between DateAdd( d, DateDiff( d, 0, TD.Date ) - 1, 0 )
                          And DateAdd( d, DateDiff( d, 0, TD.Date ),     0 )

Group By TD.Date

Update

In looking at your comments and the code, I think the problem is in your use of Between. Col Between DateA And DateB translates to Col >= DateA And Col <= DateB. I.e., it is inclusive of both end points. Instead, you need to exclude the final end point:

Select [JobNumber]
From [NCLGS].[dbo].[JobClosedDate]
Where LastInvoiceDate >= DateAdd( d, DateDiff( d, 0, GetDate() ) - 1, 0 )
    And LastInvoiceDate < DateAdd( d, DateDiff( d, 0, GetDate() ), 0 )
Order By JobNumber Desc

This will give you all job numbers that on the previous date. I.e, if today is Friday, June 10, 2011, it will give you all LastInvoiceDate values from 2011-06-09 midnight through 2011-06-09 23:59:59.

Thomas
  • 63,911
  • 12
  • 95
  • 141
  • @Thomas @Andriy -I understand what your saying, but when I pass the function GETDATE(), it returns the proper datetime: `2011-06-14 00:00:00.000` – MAW74656 Jun 14 '11 at 20:48
  • @MAW74656 - That's fine. You want SQL today's date as an actual DateTime so you can do math on it. If you are trying to return today's date as a value, return as is and format it in your report or in the output (e.g. Excel). – Thomas Jun 14 '11 at 20:55
  • @Thomas -I'm sorry, but I don't understand. Are you saying my code looks ok in light of the math requirement? – MAW74656 Jun 15 '11 at 13:56
  • @MAW74656 - I'm saying that there is a faster way to get at what you seek which is to strip the time portion from a datetime and get the dates for yesterday and today. I.e., you don't need a UDF for this. – Thomas Jun 15 '11 at 16:26
  • @MAW74656 - Btw, your function does return the correct results in terms of stripping the time portion. If you have a specific data value which is not returning the proper data, you should provide that. My guess would be in the determination of "Saturday morning". – Thomas Jun 15 '11 at 16:38
  • @MAW74656, @Thomas: Sorry about that paragraph saying that the beginning time was incorrect. I did miss the fact that the result of `DATEADD()` was being transformed by the function too. I'm really ashamed, should have double-checked before posting. – Andriy M Jun 15 '11 at 21:22
  • @Thomas -Your suggestion fixes a problem that doesn't exist (performance/readability of code). – MAW74656 Jun 21 '11 at 16:26
  • @MAW74656 - You are not being clear about where exactly the problem is. I added a query which provides a count of job numbers across a range of dates and days of the week. Where did you expect to get values and did not or visa versa? – Thomas Jun 21 '11 at 17:10
  • @MAW74656 - Btw, I do note that by using "Between" you are going to be double counting. – Thomas Jun 21 '11 at 17:12
  • @MAW74656 - Is the logic supposed to be that on a given day, it returns all invoice dates from the previous day only? I.e., on Friday Jun-10, it should return all invoice dates from 2011-06-09 00:00 through 2011-06-09 23:59? – Thomas Jun 21 '11 at 17:16
  • @Thomas -Your last comment is correct. Today I'd use GETDATE() - 1 @ 00:00:00 time as the lower limit, and GETDATE() - 1 @ 23:59.99 as the upper limit. I want all job numbers with the invoice between those. – MAW74656 Jun 21 '11 at 17:54
  • @MAW74656 - If that's the case, then the last edit I made to my answer should solve your problem. – Thomas Jun 21 '11 at 18:49
0

See Floor a date in SQL server

To strip the time portion use:

 SELECT CAST(FLOOR(CAST(CURRENT_TIMESTAMP AS float)) AS DATETIME)

This should be the fastest way. Thus

SELECT [JobNumber]
  FROM [NCLGS].[dbo].[JobClosedDate]
  WHERE LastInvoiceDate between 
       CAST((FLOOR(CAST(GETDATE() float))-1.0) AS DATETIME) AND
        CAST(FLOOR(CAST(GETDATE() AS float)) AS DATETIME)
  ORDER BY JobNumber DESC
Community
  • 1
  • 1
Hogan
  • 69,564
  • 10
  • 76
  • 117
  • The question is not about stripping time portion. This is a solution without a problem. – MAW74656 Jun 21 '11 at 16:28
  • @MAW7465 - ya got me... yours is a question without a question -- what exactly is the test data and what are the results that you don't expect? – Hogan Jun 22 '11 at 04:01
0

The procedure which updates the jobclosed table runs Monday, Tuesday, Wednesday, Thursday, & Friday mornings. It doesn't run on Saturdays, so the records aren't inserted until monday, at which time they won't be retrieved by my stored procedure. I will schedule the update job to run on Saturday's also.

I added the following before the select statement:

if datepart(dw, GETDATE()) = 7 OR datepart(dw, GETDATE()) = 1
    BEGIN
        Exec dbo.NCL_MaintainJobClosedDateTable
        --Select 'True'
    END

Which will force an update on Saturday and Sunday mornings.

MAW74656
  • 3,449
  • 21
  • 71
  • 118