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.
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 200631 September 200632 December 200633 March 200734 June 200735 September 200736 December 200740 March 200841 June 200843 September 200844 December 2008Note 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 OptimizerTG |
 |
|
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 OptimizerTG
|
 |
|
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_dataasselect survey_version_id ,convert(datetime, replace( replace( replace( survey_date , 'June ', '06/01/') , 'September ', '09/01/') , 'December ', '12/01/') , 101) as survey_datefrom (--YOUR TABLE select 30 survey_version_id, 'June 2006' survey_date union all select 31, 'September 2006' union all select 32, 'December 2006' ) dgo Be One with the OptimizerTG |
 |
|
SwePeso
Patron Saint of Lost Yaks
30421 Posts |
Posted - 2010-10-06 : 19:22:13
|
Try thisDECLARE @Sample TABLE ( SurveyID INT NOT NULL, SurveyDate VARCHAR(50) NOT NULL )INSERT @SampleSELECT 26, 'June 2006' UNION ALLSELECT 27, 'December 2005' UNION ALLSELECT 28, 'March 2006' UNION ALLSELECT 31, 'September 2006' UNION ALLSELECT 32, 'December 2006' UNION ALLSELECT 33, 'March 2007' UNION ALLSELECT 34, 'June 2007' UNION ALLSELECT 35, 'September 2007' UNION ALLSELECT 36, 'December 2007' UNION ALLSELECT 40, 'March 2008' UNION ALLSELECT 41, 'June 2008' UNION ALLSELECT 43, 'September 2008' UNION ALLSELECT 44, 'December 2008'DECLARE @SurveyID INTSET @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 SurveyIDFROM cteSourceWHERE RecID IN (3, 5, 9, 13) N 56°04'39.26"E 12°55'05.63" |
 |
|
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. |
 |
|
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" |
 |
|
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.000Add 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 |
 |
|
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 @SampleSELECT 26, 'June 2006' UNION ALLSELECT 27, 'December 2005' UNION ALLSELECT 28, 'March 2006' UNION ALLSELECT 31, 'September 2006' UNION ALLSELECT 32, 'December 2006' UNION ALLSELECT 33, 'March 2007' UNION ALLSELECT 34, 'June 2007' UNION ALLSELECT 35, 'September 2007' UNION ALLSELECT 36, 'December 2007' UNION ALLSELECT 40, 'March 2008' UNION ALLSELECT 41, 'June 2008' UNION ALLSELECT 43, 'September 2008' UNION ALLSELECT 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 SurveyIDFROM cteSourceWHERE RecID IN (3, 5, 9, 13) Errors: Msg 156, Level 15, State 1, Procedure YearVacancyReport, Line 717Incorrect 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 1Cannot update identity column 'Survey_Version_ID'. UPDATE dbo.Survey_VersionSET Survey_Version_ID = 37WHERE (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! |
 |
|
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" |
 |
|
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 717Incorrect syntax near the keyword 'WITH'.2) I do not know how to "Set [my] database to compatibility level 90 or higher" |
 |
|
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. |
 |
|
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. |
 |
|
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? |
 |
|
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 717Incorrect 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" |
 |
|
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 717Incorrect 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_date2) Survey_version_id is an IDENTITY column3) Must display desired historical dataa. Traditional Apartment vacancy surveyi. 6mos agoii. 1 year agoiii. 2 years agoiv. 3 years agob. Committee apartment vacancy survey (only valid for Kootenai & Spokane!!!!)i. Previous 4 quartersii. 2 years agoA) Change survey_version_id to be sequential with respect to their survey_datea. Must apply to past and future invalid datab. Problem: Version_ID is IDENTITY columni. Solution: UnknownB) Use a search loop to identify the most recent resulta. Most likely a WHILE loop searching for latest survey_version_idb. 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 entryC) Make derived column with converted Survey_Date data to contain Date in DATETIME data typea. Problem: Where to place columnb. Use new column as a subtraction method (ie: 9/1/2010 – 3 months = 6/1/2010 ? particular survey_version_id)D) Make derived tablea. Follow guidelines from choice CE) Search by date instead of IDa. 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. |
 |
|
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" |
 |
|
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. |
 |
|
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 @SampleSELECT 26, 'June 2006' UNION ALLSELECT 27, 'December 2005' UNION ALLSELECT 28, 'March 2006' UNION ALLSELECT 31, 'September 2006' UNION ALLSELECT 32, 'December 2006' UNION ALLSELECT 33, 'March 2007' UNION ALLSELECT 34, 'June 2007' UNION ALLSELECT 35, 'September 2007' UNION ALLSELECT 36, 'December 2007' UNION ALLSELECT 40, 'March 2008' UNION ALLSELECT 41, 'June 2008' UNION ALLSELECT 43, 'September 2008' UNION ALLSELECT 44, 'December 2008'DECLARE @SurveyID INTSET @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 SurveyIDFROM cteSourceWHERE 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 26Incorrect 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 agoInput: [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_IDHow 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!!! |
 |
|
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:00SELECT 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 feedbackThank you again!!! |
 |
|
|
|
|
|
|