Please start any new threads on our new site at https://forums.sqlteam.com. We've got lots of great SQL Server experts to answer whatever question you can come up with.

 All Forums
 SQL Server 2005 Forums
 Transact-SQL (2005)
 Searching by Date

Author  Topic 

slmgt
Starting Member

37 Posts

Posted - 2010-10-06 : 16:34:34
I have a table which contains two columns - Survey_version_id (int, Primary key) and Survey_Date (varchar(50))

Some data sample:
30 June 2006
31 September 2006
32 December 2006
33 March 2007
34 June 2007
35 September 2007
36 December 2007
40 March 2008
41 June 2008
43 September 2008
44 December 2008

Note how if the data were completely congruent, that the ID would easily correspond to the months. IE: December 2008 = 44, if we wanted December 2007, we would subtract 4 to get 40. But alas, that would give us very wrong data, March 2008. Not only that, but we would have no idea December '07 is actually 36...

My question: How can I search by dates dependent on the parameter passed to stored procedure (ID of a selected month is passed, then my job is to construct a new HISTORY report, hence getting older data) and make sure to always get the right data [even when ID is incongruent]?

For instance: User wants a report for June 2010, whose ID is 50. The number 50 is passed into my stored procedure. I then need to get the historical data from 6 months ago (Dec '09), 1 year ago (June '09), 2 years ago (June '08), and 3 years ago (June '07). With the current method of subtracting IDs, we would get ID 48, 46, 42, and 38 which would return data for Dec '09, June '09, NO month, and finally NO month when we wanted Dec '09, June '09, June '08, and June '07 respectively.

My strategy/theory (not attempted as I am lacking a method I think will work): Figure out what month is passed in (convert ID 50 --> June 2010 for example), then search for the previous data and continue the stored procedure, displaying the historical data like normal in the procedure.

How can this be accomplished?

Thank you!

TG
Master Smack Fu Yak Hacker

6065 Posts

Posted - 2010-10-06 : 16:45:21
Make [survey_date] a datetime column. You can always display the value (on your report frontend) in the desired format. That way you can easily search by date or do "date math" or date ranges.

Be One with the Optimizer
TG
Go to Top of Page

slmgt
Starting Member

37 Posts

Posted - 2010-10-06 : 16:58:13
Thanks for the response.

I would like to do just that, however I am the new DBA with a well-established database and system to manage. If I changed the data type to datetime, I would have to modify a lot of stored procedures and reports among other things.

What other way would be possible to work with the existing varchar column?

Thanks!

quote:
Originally posted by TG

Make [survey_date] a datetime column. You can always display the value (on your report frontend) in the desired format. That way you can easily search by date or do "date math" or date ranges.

Be One with the Optimizer
TG

Go to Top of Page

TG
Master Smack Fu Yak Hacker

6065 Posts

Posted - 2010-10-06 : 17:43:16
Then perhaps you can create a view off of this table which has the correct datatype. Here is an example - you'd have to build out the REPLACEs with the 9 remaining months:

create view vw_survey_data
as
select survey_version_id
,convert(datetime,
replace(
replace(
replace(
survey_date
, 'June ', '06/01/')
, 'September ', '09/01/')
, 'December ', '12/01/')
, 101) as survey_date
from

(--YOUR TABLE
select 30 survey_version_id, 'June 2006' survey_date union all
select 31, 'September 2006' union all
select 32, 'December 2006'
) d
go


Be One with the Optimizer
TG
Go to Top of Page

SwePeso
Patron Saint of Lost Yaks

30421 Posts

Posted - 2010-10-06 : 19:22:13
Try this
DECLARE	@Sample TABLE
(
SurveyID INT NOT NULL,
SurveyDate VARCHAR(50) NOT NULL
)

INSERT @Sample
SELECT 26, 'June 2006' UNION ALL
SELECT 27, 'December 2005' UNION ALL
SELECT 28, 'March 2006' UNION ALL
SELECT 31, 'September 2006' UNION ALL
SELECT 32, 'December 2006' UNION ALL
SELECT 33, 'March 2007' UNION ALL
SELECT 34, 'June 2007' UNION ALL
SELECT 35, 'September 2007' UNION ALL
SELECT 36, 'December 2007' UNION ALL
SELECT 40, 'March 2008' UNION ALL
SELECT 41, 'June 2008' UNION ALL
SELECT 43, 'September 2008' UNION ALL
SELECT 44, 'December 2008'

DECLARE @SurveyID INT

SET @SurveyID = 50

;WITH cteSource(SurveyID, RecID)
AS (
SELECT TOP(13) SurveyID,
ROW_NUMBER() OVER (ORDER BY SurveyID DESC) AS RecID
FROM @Sample
WHERE SurveyID <= @SurveyID
ORDER BY SurveyID DESC
)
SELECT SurveyID
FROM cteSource
WHERE RecID IN (3, 5, 9, 13)



N 56°04'39.26"
E 12°55'05.63"
Go to Top of Page

slmgt
Starting Member

37 Posts

Posted - 2010-10-07 : 15:53:04
What can I do to make this process more comprehensible? I am inexperienced and struggling to understand all of what has been suggested.

Basically I have a couple options, albeit to this point none have had any success. First, if I could figure out how to add identity records BACK into the Survey_Version table to make sure ALL data and make sure all future data is ALWAYS sequential, then that would solve my problem [as I could then rely on the ID to find historical data accurately]. Second, I could use the DATE specified to find the previous data using any number of differing methods. I do not think there are any other options [except maybe a hybrid using the ID then if that data doesn't exist, find the correct date, but that would mean I would need a method to search manually again].

I am willing to provide whatever information is needed to understand and complete this task. I would like to actually understand the process, because if/when it doesn't immediately work, I would like to be able to debug it. If it 'just works' that is fine too as I greatly appreciate any and all help on this matter.
Go to Top of Page

SwePeso
Patron Saint of Lost Yaks

30421 Posts

Posted - 2010-10-07 : 16:13:02
Did you try my suggestion?



N 56°04'39.26"
E 12°55'05.63"
Go to Top of Page

Michael Valentine Jones
Yak DBA Kernel (pronounced Colonel)

7020 Posts

Posted - 2010-10-07 : 16:19:09
Create a view on the table and add an additional column:
convert(datetime,Survey_Date) as Survey_Datetime


This will convert 'June 2006' to a datetime value of 2006-06-01 00:00:00.000

Add an index to the Survey_Datetime, and then you can do searches for the datetime values.

As an alternative, you could add Survey_Datetime as a computed column to your current table, and put an index on that.





CODO ERGO SUM
Go to Top of Page

slmgt
Starting Member

37 Posts

Posted - 2010-10-11 : 15:51:08
I have attempted Peso's approach with some modifications [due to errors] and have narrowed the errors down to just two:
DECLARE	@Sample TABLE
(
SurveyID INT NOT NULL,
SurveyDate VARCHAR(50) NOT NULL
)

INSERT @Sample
SELECT 26, 'June 2006' UNION ALL
SELECT 27, 'December 2005' UNION ALL
SELECT 28, 'March 2006' UNION ALL
SELECT 31, 'September 2006' UNION ALL
SELECT 32, 'December 2006' UNION ALL
SELECT 33, 'March 2007' UNION ALL
SELECT 34, 'June 2007' UNION ALL
SELECT 35, 'September 2007' UNION ALL
SELECT 36, 'December 2007' UNION ALL
SELECT 40, 'March 2008' UNION ALL
SELECT 41, 'June 2008' UNION ALL
SELECT 43, 'September 2008' UNION ALL
SELECT 44, 'December 2008'

WITH cteSource(SurveyID, RecID)
AS (
SELECT TOP 13 SurveyID,
ROW_NUMBER() OVER (ORDER BY SurveyID DESC) AS RecID
FROM @Sample
WHERE SurveyID <= @SurveyID
ORDER BY SurveyID DESC
)
SELECT SurveyID
FROM cteSource
WHERE RecID IN (3, 5, 9, 13)


Errors:
 
Msg 156, Level 15, State 1, Procedure YearVacancyReport, Line 717
Incorrect syntax near the keyword 'WITH'.
Msg 195, Level 15, State 10, Procedure YearVacancyReport, Line 720
'ROW_NUMBER' is not a recognized function name.


I am concerned that nothing is dynamic enough, because it is possible [and likely] that in the future, version_ids WILL be wrong again. I would love suggestions how I can forcefully update all survey_version_id to their specific months. For example, change Survey_version_id for March 2008 from 40 to 37. When I execute this code, it gives me
Msg 8102, Level 16, State 1, Line 1
Cannot update identity column 'Survey_Version_ID'.


UPDATE    dbo.Survey_Version
SET Survey_Version_ID = 37
WHERE (Survey_Date = 'March 2008')


Here is the design of the Survey_Version table. Optimally a script/procedure that auto-corrected IDs as related to their respective dates would be perfect, but a manual version is also more than helpful!

Please realize I am new to being a DBA and have yet to acquire the knowledge of most of SQL's abilities (ie: creating views).

I appreciate the help!
Go to Top of Page

SwePeso
Patron Saint of Lost Yaks

30421 Posts

Posted - 2010-10-11 : 15:59:20
1) ;WITH cteSource(SurveyID, RecID)
2) Set your database to compatibility level 90 or higher for working with the new windowed functions.




N 56°04'39.26"
E 12°55'05.63"
Go to Top of Page

slmgt
Starting Member

37 Posts

Posted - 2010-10-11 : 16:17:52
quote:
Originally posted by Peso

1) ;WITH cteSource(SurveyID, RecID)
2) Set your database to compatibility level 90 or higher for working with the new windowed functions.


Same error:

Msg 156, Level 15, State 1, Procedure YearVacancyReport, Line 717
Incorrect syntax near the keyword 'WITH'.

2) I do not know how to "Set [my] database to compatibility level 90 or higher"

Go to Top of Page

TimSman
Posting Yak Master

127 Posts

Posted - 2010-10-11 : 17:34:05
Is Survey_version_id an IDENTITY column? If it is, then I'm pretty certain you won't be able to accomplish what you are trying to do.
Go to Top of Page

slmgt
Starting Member

37 Posts

Posted - 2010-10-12 : 15:30:35
quote:
Originally posted by TimSman

Is Survey_version_id an IDENTITY column? If it is, then I'm pretty certain you won't be able to accomplish what you are trying to do.



Yes, survey_version-id IS an IDENTITY column. Perhaps a better method would be to either A) create a column of derived data in the table to contain the Survey_Date in DATETIME data type form or B) create an entirely new table to store the DATETIME data. My main concern with regard to this method is how I would have this table populated with data (re: converting the Survey_Date from varchar to datetime for previous instances AND future instances).

I still would prefer to use a self-correcting mechanism to keep the survey_version_id sequential always and related to their respective survey_date.
Go to Top of Page

TimSman
Posting Yak Master

127 Posts

Posted - 2010-10-12 : 16:23:16
quote:
Originally posted by slmgt

quote:
Originally posted by TimSman

Is Survey_version_id an IDENTITY column? If it is, then I'm pretty certain you won't be able to accomplish what you are trying to do.



Yes, survey_version-id IS an IDENTITY column. Perhaps a better method would be to either A) create a column of derived data in the table to contain the Survey_Date in DATETIME data type form or B) create an entirely new table to store the DATETIME data. My main concern with regard to this method is how I would have this table populated with data (re: converting the Survey_Date from varchar to datetime for previous instances AND future instances).

I still would prefer to use a self-correcting mechanism to keep the survey_version_id sequential always and related to their respective survey_date.


I think you are going to run into problems with the bolded part in the long run. What happens if a row gets deleted? Or changed?

If I understand correctly, you want a user to select some record, and find all the records based on some currently pre-determined set of criteria (6 months, 1 year, 2 years, 3 years from the selected value).

Is that an accurate statement?
Go to Top of Page

SwePeso
Patron Saint of Lost Yaks

30421 Posts

Posted - 2010-10-12 : 16:39:54
quote:
Originally posted by slmgt

Msg 156, Level 15, State 1, Procedure YearVacancyReport, Line 717
Incorrect syntax near the keyword 'WITH'.

You still can't see the semicolon before the word WITH?


N 56°04'39.26"
E 12°55'05.63"
Go to Top of Page

slmgt
Starting Member

37 Posts

Posted - 2010-10-12 : 16:49:11
quote:
Originally posted by Peso

quote:
Originally posted by slmgt

Msg 156, Level 15, State 1, Procedure YearVacancyReport, Line 717
Incorrect syntax near the keyword 'WITH'.

You still can't see the semicolon before the word WITH?


That error appears regardless of semi-colon status. I tried it WITH the semi-colon, then without [thinking it may be causing the error], then posted the code here. You asked me to put it back, so I did, but it didn't allow the code to go through anyway (throwing the same error).

@TimSman, yes, a user will select a month/year like March 2010 to generate a report. My goal is to use that date to find the historical data before it for the report.

I have compiled a list of different ways to deal with the problem:
quote:


Problem(s):
1) Survey_version_id is not sequential with respect to survey_date
2) Survey_version_id is an IDENTITY column
3) Must display desired historical data
a. Traditional Apartment vacancy survey
i. 6mos ago
ii. 1 year ago
iii. 2 years ago
iv. 3 years ago
b. Committee apartment vacancy survey (only valid for Kootenai & Spokane!!!!)
i. Previous 4 quarters
ii. 2 years ago

A) Change survey_version_id to be sequential with respect to their survey_date
a. Must apply to past and future invalid data
b. Problem: Version_ID is IDENTITY column
i. Solution: Unknown
B) Use a search loop to identify the most recent result
a. Most likely a WHILE loop searching for latest survey_version_id
b. Problem: How to find out of sequence data (re: searching 8 quarters back)?
i. Possible solution: A separate FOR loop (or same one) to find data prior to the latest missing data entry
C) Make derived column with converted Survey_Date data to contain Date in DATETIME data type
a. Problem: Where to place column
b. Use new column as a subtraction method (ie: 9/1/2010 – 3 months = 6/1/2010 ? particular survey_version_id)
D) Make derived table
a. Follow guidelines from choice C
E) Search by date instead of ID
a. Problem: Parsing month and year out of input, then searching by PREVIOUS months (ie: if June 2010 is input, search for March 2010)
F) Create view?
a. Problem: Do not know how to do this nor do I know exactly what it is.





Sorry for the formatting - it was indented correctly until I pasted it. The large letters indicate the method while the little letters indicate more specific info (re: problems with the method or ways to accomplish it). The top portion up until A) contains the requirement in very minimal terms.
Go to Top of Page

SwePeso
Patron Saint of Lost Yaks

30421 Posts

Posted - 2010-10-13 : 02:54:43
The code I posted 10/06/2010 : 19:22:13 executes and runs fine.
You must be doing something with the code that is different from the code I posted.

When I use your code posted 10/11/2010 : 15:51:08, and put back the semicolon the code works as it should.


N 56°04'39.26"
E 12°55'05.63"
Go to Top of Page

slmgt
Starting Member

37 Posts

Posted - 2010-10-13 : 15:23:12
quote:
Originally posted by Peso

The code I posted 10/06/2010 : 19:22:13 executes and runs fine.
You must be doing something with the code that is different from the code I posted.

When I use your code posted 10/11/2010 : 15:51:08, and put back the semicolon the code works as it should.


N 56°04'39.26"
E 12°55'05.63"




I am using SSMS Express on what I am told is a SQL 2000 database, but I have also heard it may be a 2005 DB. I will run the code again now and get back to you.
Go to Top of Page

slmgt
Starting Member

37 Posts

Posted - 2010-10-13 : 15:48:54
[code]DECLARE @Sample TABLE
(
SurveyID INT NOT NULL,
SurveyDate VARCHAR(50) NOT NULL
)

INSERT @Sample
SELECT 26, 'June 2006' UNION ALL
SELECT 27, 'December 2005' UNION ALL
SELECT 28, 'March 2006' UNION ALL
SELECT 31, 'September 2006' UNION ALL
SELECT 32, 'December 2006' UNION ALL
SELECT 33, 'March 2007' UNION ALL
SELECT 34, 'June 2007' UNION ALL
SELECT 35, 'September 2007' UNION ALL
SELECT 36, 'December 2007' UNION ALL
SELECT 40, 'March 2008' UNION ALL
SELECT 41, 'June 2008' UNION ALL
SELECT 43, 'September 2008' UNION ALL
SELECT 44, 'December 2008'

DECLARE @SurveyID INT

SET @SurveyID = 50

;WITH cteSource(SurveyID, RecID)
AS (
SELECT TOP 13 SurveyID,
ROW_NUMBER() OVER (ORDER BY SurveyID DESC) AS RecID
FROM @Sample
WHERE SurveyID <= @SurveyID
ORDER BY SurveyID DESC
)
SELECT SurveyID
FROM cteSource
WHERE RecID IN (3, 5, 9, 13)[/code]

All I did was remove the parantheses from TOP(13) because I was receiving an error there. However with the rest of the code intact, I still receive these two errors:

[code]
Msg 156, Level 15, State 1, Line 26
Incorrect syntax near the keyword 'WITH'. //this error occurs on ";WITH cteSource(SurveyID, RecID)"
Msg 195, Level 15, State 10, Line 29
'ROW_NUMBER' is not a recognized function name.//this error occurs on "ROW_NUMBER() OVER (ORDER BY SurveyID DESC) AS RecID"[/code]

@Peso, I really appreciate the work on this query for me. Do you have an example of what I could use in my stored procedure to help me accomplish one of my two preferred ideas: B or E where B is "Use a search loop to identify the most recent result" and E is "Parsing month and year out of input, then searching by PREVIOUS months (ie: if June 2010 is input, search for March 2010)" with my #1 preferred idea being constructing a search loop to find the previous quarter.

How the loop should work:
Type of Survey: NORMAL
Desired Historical Data: 6mos ago, 1 year ago, 2 years ago, 3 years ago
Input: [Month and Year] (June 2010)
Use existing Survey_ID (50), subtract # of quarters (2), if that record is NULL, SELECT TOP 1 WHERE Survey_Version_ID < Survey_ID


How this example would work: 50-2 = 48 ==> December 2009 (Correct), 50-4 = 46 ==> June 2009 (Correct), 50-8 = 42 ==> NULL (WRONG, SELECT TOP 1 Survey_Version_ID WHERE Survey_Version_ID < Survey_ID(42) which would output 41 ==> June 2008 (Correct!), and 50-12 = 38 ==> NULL (WRONG, SELECT TOP 1 Survey_Version_ID WHERE Survey_Version_ID < Survey_ID(38) which would output 36 ==> December 2007 (WRONG - short of searching by MONTH/YEAR, this is unavoidable :-\)


I struck that portion out because I found a glaring problem; unless the version_id is only ONE (1) number off, it will fail. Could someone please help me design this procedure to search by DATE (whether using a derived column/table or not), because then we would get the right answer EVERY time?

Thank you!!!
Go to Top of Page

slmgt
Starting Member

37 Posts

Posted - 2010-10-13 : 16:57:45
Ok sorry for the multiple postings, but each post is independent.

I made some great progress! I have created a [simple] way to convert my STRING dates to DATETIME, then found a function to do DATETIME arithmetic! For anyone else who needs this:

convert(smalldatetime, 'October 2010', 100)
will output 2010-10-01 00:00:00
SELECT DATEADD(m, 1, (convert(smalldatetime, 'October 2010', 100)))
will output 2010-[b]11[b]-01 00:00:00 (note it moved 1 month forward)

Here is my latest query; it works perfectly to retrieve the previous quarter based on converting the string date to a datetime date, then subtracting 3 months (1 quarter). I will modify it to be dynamic (using variables for months to subtract and for the version_id stuff).

(SELECT survey_version_id FROM dbo.Survey_Version WHERE Survey_Date = (SELECT DATEADD(m,-3, (convert(datetime, (SELECT Survey_Date FROM dbo.Survey_Version WHERE Survey_Version_ID = 51))))))

Let me know if you have anymore feedback

Thank you again!!!
Go to Top of Page
   

- Advertisement -