2

I have created a query which displays different data when being executed in Microsoft SQL Server Management Studio express than it does when outputting in a browser either using cfdump or cfoutput.

Here is the query:

select count(stat_id) as val, month(status_date) as mnth, year(status_date) as yr
from task_status ts
join appraisal.dbo.employee e on e.userID = ts.user_ID
where e.comp = 1
and e.dept = 2
and e.archive != 1
and ts.status_date between '2016-10-01 00:00:00' AND '2017-10-01 00:00:00'
group by month(status_date), year(status_date)
order by year(status_date), month(status_date)

The expected results, and results seen in Management Studio are:

YR  MNTH YR
1   10  2016
1   11  2016
9   2   2017
4   3   2017
3   4   2017
18  5   2017
6   6   2017
1   7   2017 

However, results seen from the browser are:

YR  MNTH    VAL
2016    1   7
2016    2   13
2016    3   5
2016    4   5
2016    5   1
2016    6   4
2016    7   2
2016    10  1
2016    11  1 

Any suggestions as to what may be causing this would be most welcome, as I have no idea why there is a difference.

Miguel-F
  • 13,450
  • 6
  • 38
  • 63
weekev126
  • 23
  • 2
  • 3
    Please include the code showing how you generated that output from ColdFusion. Also, are you sure that the datasource being used by ColdFusion is pointing to the same database server and same database table as the query you ran from SQL Studio? – Miguel-F Nov 02 '17 at 12:35
  • What version of ColdFusion are you using? What version of SQL Server are you using? Does the CF version behave differently if you use "<>" versus "!="? You may want to consider using CFQUERYPARAM w/CF_SQL_DATE as it eliminates the need to format the dates. – James Moberg Nov 02 '17 at 13:51
  • I am simply using cfdump to see the data output: select count(stat_id) as val, month(status_date) as mnth, year(status_date) from task_status ts join appraisal.dbo.employee e on e.userID = ts.user_ID where e.comp = 1 and e.dept = 2 and e.archive != 1 and e.noCompetency != 1 and ts.status_date between '2016-10-01 00:00:00' AND '2017-10-01 00:00:00' group by month(status_date), year(status_date) order by year(status_date), month(status_date) – weekev126 Nov 02 '17 at 14:31
  • using ColdFusion 9, and SQL Server 2005 – weekev126 Nov 02 '17 at 14:36
  • 1
    Not that it would ever happen to me, but I've heard rumors about people doing this sort of thing and then discovering they were comparing results from different databases - test vs prod for example. – Dan Bracuk Nov 02 '17 at 14:45
  • Felt like a complete idiot for a second, but then realised this is not the case here. Still baffled! – weekev126 Nov 02 '17 at 16:17
  • The query in your question and in the cf code you just posted are different. Is this related to the issue? – Dan Roberts Nov 03 '17 at 13:48
  • Do you have some sample data you can share? I would triple-check again that you're two queries are looking at the same data. What language or localization setting are you using for SQL? Try using `SET DATEFORMAT ydm; GO` before your query to make sure your query, your SQL server and your CF server agree what '2017-10-01' means. – Shawn Nov 03 '17 at 14:10
  • Do you have any data in December 2016 or before January 10, 2017? You CF output seems to indicate that it's searching Jan 10, 2016 to Jan 10, 2017. I also see you're in the UK. The localization settings may be reading a different date than you think they are. – Shawn Nov 03 '17 at 14:15
  • Run this in a `cfquery`: `SELECT getUTCDate() AS UTCDate` and dump that, then run `#getLocale()#. Are they showing different things? I suspect that CF or SQL is reading your date string as yyyy-dd-mm, which doesn't seem to be what you intend. – Shawn Nov 03 '17 at 14:41

1 Answers1

1

EDIT:

Try changing the dates in your query to

select count(stat_id) as val, month(status_date) as mnth, year(status_date) as yr
from task_status ts
INNER JOIN appraisal.dbo.employee e on e.userID = ts.user_ID
    AND e.comp = 1
    AND e.dept = 2
    AND  e.archive != 1
WHERE ts.status_date between '20161001' AND '20171001'
group by year(status_date), month(status_date)
order by year(status_date), month(status_date)

See ISO 8601. You could also change the dates to '2016-10-01T00:00:00' AND '2017-10-01T00:00:00'.

I believe your date may be getting interpreted as a string that is read as YYYY-DD-MM and giving the wrong range when passed to SQL through ColdFusion or the JVM.

=========================================================================

ORIGINAL:

This is more of a personal preference comment:

Change your JOIN syntax to move the conditions out of the WHERE and into the JOIN.

select count(stat_id) as val, month(status_date) as mnth, year(status_date) as yr
from task_status ts
INNER JOIN appraisal.dbo.employee e on e.userID = ts.user_ID
    AND e.comp = 1
    AND e.dept = 2
    AND  e.archive != 1
WHERE ts.status_date between '2016-10-01 00:00:00' AND '2017-10-01 00:00:00'
group by year(status_date), month(status_date)
order by year(status_date), month(status_date)

When JOINing tables, it helps to imagine the sets of data that you're working with. When you specify the conditions in the WHERE, you will be creating a big JOIN and then filtering out those results with the WHERE clause. I think newer versions of SQL are a smarter with their optimizer, but I know that 2005 can return different results when conditions are in a LEFT OUTER JOIN vs a WHERE. INNER JOIN won't make a difference, but OUTER can.

I also changed the order in your GROUP BY. It shouldn't change the results, but it's cleaner and more consistent with the grouping of the way the data is likely being used (group by years, then the months of those years).

And a personal preference: rather than just using JOIN, I like adding INNER JOIN, just to make it clearer what specifically I'm doing.

Shawn
  • 4,758
  • 1
  • 20
  • 29
  • Also, I would highly suggest looking into creating a Date Dimension (https://www.mssqltips.com/sqlservertip/4054/creating-a-date-dimension-or-calendar-table-in-sql-server/). This is the kind of query that these absolutely help with. And if you have an index on your status_date, you'll be able to use it. – Shawn Nov 02 '17 at 21:37
  • Just using join is different logic than using left outer join. – Dan Bracuk Nov 03 '17 at 01:19
  • As Dan points out, changing the join to a left outer join doesn't return the results I want. I have tried changing the order of the group by, and as per original post, the results using the query analyser are as expected, but when using cfdump to output the results they only contained 2016 in the year column – weekev126 Nov 03 '17 at 11:16
  • @DanBracuk My mistake. JOIN = INNER JOIN. This is why I like being specific with the type of JOIN: INNER, LEFT OUTER, etc. :-) So moving the conditions up, though still my preference, will not change the final output. – Shawn Nov 03 '17 at 13:47