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
 General SQL Server Forums
 New to SQL Server Programming
 Need help with normalizing queries

Author  Topic 

gena_mak
Starting Member

26 Posts

Posted - 2010-02-05 : 14:34:10
Hi
I inherited quite complex system that I can not change at this stage. It uses a lot of sub-queries and I feel that there is a better way to construct such queries so, may be someone will be kind enough to advice.
Here is the table #tCustomerPayments that stores customer weekly payments over one year from Jan 1 to Dec 31. These payments can change over time and in some cases retroactively. When new payment is added starting with some date, it is inserted in proper date interval starting with that date and ending with year end (query #13), and all following records for this customer get overridden by setting active_record field to the customerpayment_id of newly inserted record (query #15). In query #14 dates are aligned in proper sequence.

I tried to simplify the queries in question.

Here is the definition:
=====================================================================
declare @newID int

create table #tCustomerPayments (
customerpayment_id int not null identity(1,1),
customer_id int,
amount float,
start_date datetime,
end_date datetime,
active_record int
)

set nocount on
-- populate table
-- query #1 customer 1
insert into #tCustomerPayments (customer_id, amount, start_date, end_date)
values (1, 200, '1/1/2009', '2/11/2009')

-- query #2
insert into #tCustomerPayments (customer_id, amount, start_date, end_date)
values (1, 100, '2/12/2009', '7/21/2009')

-- query #3
insert into #tCustomerPayments (customer_id, amount, start_date, end_date)
values (1, 80, '7/22/2009', '9/21/2009')

-- query #4
insert into #tCustomerPayments (customer_id, amount, start_date, end_date)
values (1, 140, '9/22/2009', '10/17/2009')

-- query #5
insert into #tCustomerPayments (customer_id, amount, start_date, end_date)
values (1, 280, '10/18/2009', '10/18/2009')

-- query #6
insert into #tCustomerPayments (customer_id, amount, start_date, end_date)
values (1, 290, '10/18/2009', '10/18/2009')

-- query #7
insert into #tCustomerPayments (customer_id, amount, start_date, end_date)
values (1, 250, '10/19/2009', '12/31/2009')

-- customer 2
-- query #8
insert into #tCustomerPayments (customer_id, amount, start_date, end_date)
values (2, 1200, '1/1/2009', '5/25/2009')

-- query #9
insert into #tCustomerPayments (customer_id, amount, start_date, end_date)
values (2, 25, '5/26/2009', '11/29/2009')

-- query #10
insert into #tCustomerPayments (customer_id, amount, start_date, end_date)
values (2, 400, '11/30/2009', '12/31/2009')

-- customer 3
-- query #11
insert into #tCustomerPayments (customer_id, amount, start_date, end_date)
values (3, 700, '1/1/2009', '12/31/2009')
-- end of populate table

-- pull all active records
-- query #12
SELECT * FROM #tCustomerPayments
WHERE active_record IS NULL
ORDER BY customer_id, customerpayment_id

-- updates to payment amounts done in Jan, 2010 retroactively
-- customer's 1 payments become $150 starting 8/23/2009 to the end of the year
-- query #13
insert into #tCustomerPayments (customer_id, amount, start_date, end_date)
values (1, 150, '8/23/2009', '12/31/2009')

SET @newID = @@IDENTITY

-- update record with start date earlier than 8/23/2009 and end_date later than 8/23/2009 to make end date 8/22/2009 to make proper sequence
-- query #14
UPDATE #tCustomerPayments
SET end_date = DateAdd(dd,-1,'8/23/2009')
WHERE customer_id = 1
AND start_date < '8/23/2009' AND end_date > '8/23/2009'
AND active_record IS NULL

-- all amounts that were active after that date become inactive by setting active_record to the @@identity of just inserted record
-- query #15
UPDATE #tCustomerPayments
SET active_record = @newID
WHERE customer_id = 1
AND start_date > '8/23/2009'

-- pull all active records
-- query #16
SELECT * FROM #tCustomerPayments
WHERE active_record IS NULL
ORDER BY customer_id, customerpayment_id

-- query #17
SELECT * FROM #tCustomerPayments
WHERE active_record IS NOT NULL
ORDER BY customer_id, customerpayment_id

----------------------------------------------------------------------------
-- we need to get latest payment data for customer #1
-- query #18
SELECT * FROM #tCustomerPayments c
WHERE customer_id = 1
AND active_record IS NULL
AND customerpayment_id =
(
SELECT TOP 1 customerpayment_id
FROM #tCustomerPayments
WHERE customer_id = c.customer_id
AND active_record IS NULL
ORDER BY end_date DESC, customerpayment_id DESC
)

-- we need to get payment data for customer #1 as of 5/21/2009 (May 21, 2009)
-- query #19
SELECT * FROM #tCustomerPayments c
WHERE customer_id = 1
AND active_record IS NULL
AND customerpayment_id =
(
SELECT MAX(customerpayment_id) -- max() is used because in some cases payment can change few times in one day as in insert query #5 and #6
FROM #tCustomerPayments
WHERE customer_id = c.customer_id
AND active_record IS NULL
AND DateDiff(dd,start_date,'5/21/2009')>=0
AND DateDiff(dd,'5/21/2009',end_date)>=0
)
------------------------------------------------------------------------

drop table #tCustomerPayments
set nocount off

=====================================================================
Basically, in queries number #18 and #19 to pull latest customer record or as of some date, used sub-query that relies on customerpayment_id. It works fine but, is there better way to pull it without using this sub-query?

Thank you

Kristen
Test

22859 Posts

Posted - 2010-02-06 : 01:08:23
haven't had time to look at this in detail, but one thing I spotted:

AND DateDiff(dd,start_date,'5/21/2009')>=0
AND DateDiff(dd,'5/21/2009',end_date)>=0

this is always better done as:

AND start_date < '20090522'
AND end_date >= '20090521'

This allows SQL to use any available index on start_date or end_date (whereas if you include the date column in function then indexes are not used).

Note that the start condition is LESS THAN 'one-day-after-the-end-point' - this allows the start_date to include a time element, i.e. up to 23:59.

I've also changed your string dates to 'yyyymmdd' which is the only unambiguous implicit format that is guaranteed to work. Your style is probably fine on the server you use, but is not transportable to servers with different locale settings. (Date strings in m/d/y order can be explicitly cast of course)
Go to Top of Page

visakh16
Very Important crosS Applying yaK Herder

52326 Posts

Posted - 2010-02-06 : 06:14:29
for query 18 isnt this enough?


SELECT TOP 1 *
FROM #tCustomerPayments
WHERE customer_id = 1
AND active_record IS NULL
ORDER BY end_date DESC, customerpayment_id DESC


and for query 19

SELECT TOP 1 * FROM #tCustomerPayments c
WHERE customer_id = 1
AND active_record IS NULL
AND start_date < '20090522'
AND end_date >= '20090521'
ORDER BY customerpayment_id DESC
Go to Top of Page

gena_mak
Starting Member

26 Posts

Posted - 2010-02-08 : 09:11:03
Kristen
I am not concerned about day format as I have ODBC wrapper before the date is applied as argument to stored procedures, functions or queries. As for DateDiff(), I know some advice against that, some... for. The DateDiff() helps to establish date frame that relies on day only, I dont care about time and this is very important, especially its important because the system is used over few time zones.

visakh16
SELECT TOP 1... I had it failed in couple of cases, it is important to get this unique customerpayment_id in WHERE clause.

For my question, I was thinking in order to improve performance, perhaps to switch to derived tables or views (can be too much work). May be some sort of grouping would work better.
Go to Top of Page

visakh16
Very Important crosS Applying yaK Herder

52326 Posts

Posted - 2010-02-08 : 09:22:00
SELECT TOP 1... I had it failed in couple of cases, it is important to get this unique customerpayment_id in WHERE clause.

sorry didnt understand why it failed. can you explain that?
Go to Top of Page

Kristen
Test

22859 Posts

Posted - 2010-02-08 : 09:32:23
"I am not concerned about day format as I have ODBC convert funciton wrapper before the date is applied as argument to stored procedures, functions or queries."

OK (but dates in string format, as examples on this forum for instance, will perform differently around the world )

Is your application sending Dates via ODBC as just the Date, or including a time also - i.e. a DateTime?

If it is just the date then

AND start_date < DATEADD(Day, 1, @CutoffDate)
AND end_date >= @CutoffDate

will include values for start_date (including any time) that is on, or before, @CutoffDate - that is to say earlier than midnight-following the cutoff date; and end_date is midnight on the @CutoffDate (i.e. midnight at the start of the cutoff date) or later.

If the parameters from your application include time components as well the parameters can be "rounded" to midnight to remove them:

AND start_date < DATEADD(Day, DATEDIFF(Day, 0, @CutoffDate), 1)
AND end_date >= DATEADD(Day, DATEDIFF(DAy, 0, @CutoffDate), 0)

both those methods should use indexes available for the Start/End date columns.

"As for DateDiff(), I know some advice against that, some... for."

I'd be interested to know anything against please.

In this context if you apply DateDiff() to the columns e.g.

AND DateDiff(dd,start_date, @CutoffDate)>=0
AND DateDiff(dd,@CutoffDate, end_date)>=0

indexes will not be used in the query plan, resulting in a scan of all rows in the table - which, for a large table, will be much slower than using a query plan which uses the indexes.

"The DateDiff() helps to establish date frame that relies on day only, I dont care about time and this is very important, especially its important because the system is used over few time zones."

OK, my examples did assume that the time was to be ignored
Go to Top of Page

gena_mak
Starting Member

26 Posts

Posted - 2010-02-08 : 09:55:34
visakh16:

It failed to pull right record, I cant remember particular. I will try to find it. The thing is, my example here is quite simplified.

The structure of the tables involved is quite a bit more. Here we have few more joined tables for payment period for expample where payment period is by itself has unique primary key which is has foreign key present in what is here #tCustomerPayments.
Basically in very short whithin context of the quesion, as it takes lot more to expand, it looks like that:
customer table (top table for customer)
payment plan (top table for plan, there are also groups of payments and item payments within groups...)
payment plan -> payment period
payment group -> payment item
customer -> payment period -> payments (junction table for customer payments within payment period on this plan, there are multiple payments for multiple items, read records for each customer and customer can change items, options, pay methods...)

if I expand only little bit more:
create table #tCustomerPayments (
customerpayment_id int not null identity(1,1),
cust_payperiod_id int foreign key tCustPayPeriods,
payitem_id int foreign key tPayItems,
payitem_option_id int foreign key tPayOptions,
paymethod_id int foreign key tPaymethods,
customer_id int foreign key tCustomers,
amount float,
start_date datetime,
end_date datetime,
active_record int
)

So, when I put everything together and try to pull right record, the query looks quite more complex than I presented here. So, my question is sort of more general on how to improve performance, as I see too many sub-selects.
Go to Top of Page

gena_mak
Starting Member

26 Posts

Posted - 2010-02-08 : 10:14:50
quote:
Originally posted by Kristen

"I am not concerned about day format as I have ODBC convert funciton wrapper before the date is applied as argument to stored procedures, functions or queries."

OK (but dates in string format, as examples on this forum for instance, will perform differently around the world )

Is your application sending Dates via ODBC as just the Date, or including a time also - i.e. a DateTime?

If it is just the date then

AND start_date < DATEADD(Day, 1, @CutoffDate)
AND end_date >= @CutoffDate

will include values for start_date (including any time) that is on, or before, @CutoffDate - that is to say earlier than midnight-following the cutoff date; and end_date is midnight on the @CutoffDate (i.e. midnight at the start of the cutoff date) or later.

If the parameters from your application include time components as well the parameters can be "rounded" to midnight to remove them:

AND start_date < DATEADD(Day, DATEDIFF(Day, 0, @CutoffDate), 1)
AND end_date >= DATEADD(Day, DATEDIFF(DAy, 0, @CutoffDate), 0)

both those methods should use indexes available for the Start/End date columns.

"As for DateDiff(), I know some advice against that, some... for."

I'd be interested to know anything against please.

In this context if you apply DateDiff() to the columns e.g.

AND DateDiff(dd,start_date, @CutoffDate)>=0
AND DateDiff(dd,@CutoffDate, end_date)>=0

indexes will not be used in the query plan, resulting in a scan of all rows in the table - which, for a large table, will be much slower than using a query plan which uses the indexes.

"The DateDiff() helps to establish date frame that relies on day only, I dont care about time and this is very important, especially its important because the system is used over few time zones."

OK, my examples did assume that the time was to be ignored



Kristen

The date gets to the query in this format {d '2010-02-04'} and in some cases when used in stored procedure with time. I mentioned before that I ingnore the time because we do not have requirement anywhere to use it, only DAY, MONTH, YEAR. I am reluctanct to switch to date data type in stored procedures, may be in future we might need time too, so I use datetime in functions and procedures.
Thank you for pointing about indexes. I will try to experiment to see if it helps to improve performance.
Go to Top of Page

Transact Charlie
Master Smack Fu Yak Hacker

3451 Posts

Posted - 2010-02-08 : 10:18:35
Hi gena_mak.

I was going to suggest a few improvements but I've read over what Kristen and Visakh have posted and everything they say is great advice for the information you posted.

This section:

-- we need to get latest payment data for customer #1
-- query #18
SELECT * FROM #tCustomerPayments c
WHERE customer_id = 1
AND active_record IS NULL
AND customerpayment_id =
(
SELECT TOP 1 customerpayment_id
FROM #tCustomerPayments
WHERE customer_id = c.customer_id
AND active_record IS NULL
ORDER BY end_date DESC, customerpayment_id DESC
)

Where visakh simplified this to get what he posted but this doesn't really make sense. Why would want to find the top 1 for a particular person this way?

Were you actually wanting the TOP 1 details per customer in the table ordered by some set of columns? If so that isn't what you said you wanted.

Kristen's advice on the date comparisons is gold and you seem to be completely ignoring it.

If you want accurate help then my advice is to split the problem in smaller pieces. Post the *full* (not simplified) version of those problems and someone will not be able to resist showing how kewl he or she is by optimising them.

Posting something that is different to what you actually want to fix is meaningless unless you get the root cause of the problem absolutely right. I think you are putting people off from helping you here.

Here are a few questions that you can answer which will help people help you:

---------------------------------

1) Which version of SQL Server are you using? -- this is important as there are many methods of optimisation that work well in 2005 or later that are not available in 2000. In particular it is often easy to eliminate sub selects with either ROW_NUMBER() or OUTER/CROSS APPLY

2) Please provide the full table structure (including any indices present) for the tables involved.

3) Please provide the *actual* sql that you want to improve. There's nothing more likely to turn someone off from helping than when they post a solution and the OP says -- actually that isn't relevant because....

4) If possible please provide some data. This doesn't have to be actual data and it's probably better from a security point of view that it isn't but it should be representative of your actual data.

----------------

If you do this then you'll get awesome help here. Your problems will vanish.

I'm not having a go at you, but if you stop for a moment and have a look at your posts I think you'll find that you aren't coming across very well.

Best of luck,


Charlie
===============================================================
Msg 3903, Level 16, State 1, Line 1736
The ROLLBACK TRANSACTION request has no corresponding BEGIN TRANSACTION
Go to Top of Page

gena_mak
Starting Member

26 Posts

Posted - 2010-02-08 : 10:30:08
quote:
Originally posted by Transact Charlie

Hi gena_mak.

I was going to suggest a few improvements but I've read over what Kristen and Visakh have posted and everything they say is great advice for the information you posted.

This section:

-- we need to get latest payment data for customer #1
-- query #18
SELECT * FROM #tCustomerPayments c
WHERE customer_id = 1
AND active_record IS NULL
AND customerpayment_id =
(
SELECT TOP 1 customerpayment_id
FROM #tCustomerPayments
WHERE customer_id = c.customer_id
AND active_record IS NULL
ORDER BY end_date DESC, customerpayment_id DESC
)

Where visakh simplified this to get what he posted but this doesn't really make sense. Why would want to find the top 1 for a particular person this way?

Were you actually wanting the TOP 1 details per customer in the table ordered by some set of columns? If so that isn't what you said you wanted.

Kristen's advice on the date comparisons is gold and you seem to be completely ignoring it.

If you want accurate help then my advice is to split the problem in smaller pieces. Post the *full* (not simplified) version of those problems and someone will not be able to resist showing how kewl he or she is by optimising them.

Posting something that is different to what you actually want to fix is meaningless unless you get the root cause of the problem absolutely right. I think you are putting people off from helping you here.

Here are a few questions that you can answer which will help people help you:

---------------------------------

1) Which version of SQL Server are you using? -- this is important as there are many methods of optimisation that work well in 2005 or later that are not available in 2000. In particular it is often easy to eliminate sub selects with either ROW_NUMBER() or OUTER/CROSS APPLY

2) Please provide the full table structure (including any indices present) for the tables involved.

3) Please provide the *actual* sql that you want to improve. There's nothing more likely to turn someone off from helping than when they post a solution and the OP says -- actually that isn't relevant because....

4) If possible please provide some data. This doesn't have to be actual data and it's probably better from a security point of view that it isn't but it should be representative of your actual data.

----------------

If you do this then you'll get awesome help here. Your problems will vanish.

I'm not having a go at you, but if you stop for a moment and have a look at your posts I think you'll find that you aren't coming across very well.

Best of luck,


Charlie
===============================================================
Msg 3903, Level 16, State 1, Line 1736
The ROLLBACK TRANSACTION request has no corresponding BEGIN TRANSACTION




Charlie

Thank you for input. I am not ingnoring, I am learning :)
Its very helpful as I am not advanced SQL programmer, any advice is very helpful, just difficult to explain without the context. Easy part is we use SQL 2005.
Now, I am trying to figure which part of the system to show here as it contains about 250 tables and, not to confuse people.
Go to Top of Page

Kristen
Test

22859 Posts

Posted - 2010-02-08 : 10:30:40
"The date gets to the query in this format {d '2010-02-04'}"

Perfect then!

"I am reluctanct to switch to date data type in stored procedures, may be in future we might need time too, so I use datetime in functions and procedures."

Ah, sorry if I implied changing datatype, I certainly didn't mean that, my suggestions are just designed to remove the time-part of a datetime datatype. I haven't used DATE datatype in SQL 2008 for anything yet either!
Go to Top of Page

Transact Charlie
Master Smack Fu Yak Hacker

3451 Posts

Posted - 2010-02-08 : 10:53:27
Gena_mak

Its good that you are on 2005. There will be lots of ways to remove subqueries.

I'm posting this to illustrate Kristen's advice.

This sql will build a dataset of random dates

IF OBJECT_ID('tempDb..#testTable') IS NOT NULL DROP TABLE #testTable

CREATE TABLE #testTable (
[Id] INT IDENTITY(1,1) PRIMARY KEY NONCLUSTERED
, [startDate] DATETIME
, [endDate] DATETIME
)

CREATE CLUSTERED INDEX IX_ID_START_END ON #testTable ([startDate], [endDate])

GO

INSERT #testTable ([startDate], [endDate])
SELECT
CAST(CAST(CAST(NEWID() AS VARBINARY(2)) AS INT) AS DATETIME)
, CAST(CAST(CAST(NEWID() AS VARBINARY(2)) AS INT) AS DATETIME)
FROM
(SELECT 1 AS [1] UNION SELECT 2 AS [2] UNION SELECT 3 AS [3]) a
CROSS JOIN (SELECT 1 AS [1] UNION SELECT 2 AS [2] UNION SELECT 3 AS [3]) b
CROSS JOIN (SELECT 1 AS [1] UNION SELECT 2 AS [2] UNION SELECT 3 AS [3]) c
CROSS JOIN (SELECT 1 AS [1] UNION SELECT 2 AS [2] UNION SELECT 3 AS [3]) d
CROSS JOIN (SELECT 1 AS [1] UNION SELECT 2 AS [2] UNION SELECT 3 AS [3]) e
CROSS JOIN (SELECT 1 AS [1] UNION SELECT 2 AS [2] UNION SELECT 3 AS [3]) f
CROSS JOIN (SELECT 1 AS [1] UNION SELECT 2 AS [2] UNION SELECT 3 AS [3]) g
CROSS JOIN (SELECT 1 AS [1] UNION SELECT 2 AS [2] UNION SELECT 3 AS [3]) h
GO

You'll end up with a temp table with 3 to the eight rows of random dates. There is a clustered index over both dates but you can change that to suit your requirement. You need a lot of rows to make sure that the optimisation engine wouldn't just choose an index SCAN as the fastest method for all queries.

You can then play with this to see the benefits that Kristen is talking about.

Here is a short example script. The important bit is really the SET SHOWPLAN_ALL ON. This has to be the only command in a batch and you'll have to run it in the same Management Studio window the temp table was created in. You can then rerun the two SELECT statements below it to see the index usage.


-- This must be the only command in the batch -- it shows you the execution plan and index use
SET SHOWPLAN_ALL ON
GO

-- DATEDIFF EXAMPLE
-- Find any rows with startdate of 2010-Jan-01
SELECT
*
FROM
#testTable
WHERE
DATEDIFF(DAY, [startDate], '20100101') = 0
GO

-- >= < EXAMPLE
SELECT
*
FROM
#testTable
WHERE
[startDate] >= '20100101'
AND [startDate] < '20100102'

You should see that the second query (which will return the same results as the first) will use an INDEX SEEK whereas the first will use an INDEX SCAN. when you scan the index you have to look at the value of every row in the table. when you SEEK then you don't.



Charlie
===============================================================
Msg 3903, Level 16, State 1, Line 1736
The ROLLBACK TRANSACTION request has no corresponding BEGIN TRANSACTION
Go to Top of Page

Transact Charlie
Master Smack Fu Yak Hacker

3451 Posts

Posted - 2010-02-08 : 10:56:19
Just a short note to say that with SET SHOWPLAN_ALL ON if you run the whole set of scripts again (the parts that generate the dates) then you'll get an error

Msg 2714, Level 16, State 6, Line 3
There is already an object named '#testTable' in the database.


You can ignore it -- if you look at your results tab you'll still see the execution plan.

Here's the expected reslts

1) For the DATEDIFF example

EstimateRows EstimateIO EstimateCPU AvgRowSize
729 NULL NULL NULL
729 0.01868056 0.0073741 27


2) For the >= < Example

EstimateRows EstimateIO EstimateCPU AvgRowSize
1 NULL NULL NULL
1 0.003125 0.0001581 27


So even on this very small dataset the IO costs are improved by a factor of 6. The CPU improvement is even better.
Charlie
===============================================================
Msg 3903, Level 16, State 1, Line 1736
The ROLLBACK TRANSACTION request has no corresponding BEGIN TRANSACTION
Go to Top of Page

gena_mak
Starting Member

26 Posts

Posted - 2010-02-08 : 11:25:39
quote:

SELECT
*
FROM
#testTable
WHERE
DATEDIFF(DAY, [startDate], '20100101') = 0
GO

-- >= < EXAMPLE
SELECT
*
FROM
#testTable
WHERE
[startDate] >= '20100101'
AND [startDate] < '20100102'
[/code]



Charlie

May be a dumb question but, just to make sure I covered that. Will this matter if server is located in one time zone and query is executed in another where in our time zone is 11:40PM (23:40) Feb 8, and somewhere where the query is executed its 5AM (5 O'clock) Feb 9?

Gena
Go to Top of Page

Transact Charlie
Master Smack Fu Yak Hacker

3451 Posts

Posted - 2010-02-08 : 11:27:35
doesn't matter -- the query is executed on the server. Even if you referenced a function like GETDATE() it would return the system time of the db server. As long as the dates in the table are accurate......


Charlie
===============================================================
Msg 3903, Level 16, State 1, Line 1736
The ROLLBACK TRANSACTION request has no corresponding BEGIN TRANSACTION
Go to Top of Page

Kristen
Test

22859 Posts

Posted - 2010-02-08 : 11:33:03
"May be a dumb question but, just to make sure I covered that. Will this matter if server is located in one time zone and query is executed in another where in our time zone is 11:40PM (23:40) Feb 8, and somewhere where the query is executed its 5AM (5 O'clock) Feb 9?"

I was going to raise that earlier, but thought it would just be clouding the issue ... maybe not ...

Lets say you have offices in Europe and USA.

If I am in Europe its 08-Feb and, lets say, its still 07-Feb in USA.

Lets say the server is in USA.

If I record some data what date is used? Do I manually enter the date (i.e. into your application), and thus I enter 08-Feb, or does the server allocate the date automatically - i.e. 07-Feb? or does the application use the date/time on my PC (which could be anything, of course, because my system clock could be wrong).

When the clocks go forward/back that makes a further mess of things of course ...
Go to Top of Page

Transact Charlie
Master Smack Fu Yak Hacker

3451 Posts

Posted - 2010-02-08 : 11:40:11
ah true -- I thought gena_mak meant that:

With the same set of data and the same query

Would the results be different if run from a different client connection in different time zone.


Charlie
===============================================================
Msg 3903, Level 16, State 1, Line 1736
The ROLLBACK TRANSACTION request has no corresponding BEGIN TRANSACTION
Go to Top of Page

Kristen
Test

22859 Posts

Posted - 2010-02-08 : 11:45:56
"I thought gena_mak meant that"

Could be that too, I hadn't thought of that
Go to Top of Page

gena_mak
Starting Member

26 Posts

Posted - 2010-02-08 : 12:19:57
Yea, I messed the quesiton up a bit. I meant to compare dates submitted from different time zones where the date is the same but time is different. I such cases even if one record would be submitted earlier but carry date stamp later than the other. However primary key (identity) will be greater value than the other one.
Let say I am in Seattle and its 11AM
Someone else in New York and its 8AM

I submitted my query and saved it with date stamp of 11AM on Feb 8 - record primary key is 22
Someone else does the same after that and date stamp is 8AM - record primary key is 27

In this case, will the server convert to its local time or will save 11AM and 8AM?

Sorry if confused you, trying to manage few things here
Go to Top of Page

Kristen
Test

22859 Posts

Posted - 2010-02-08 : 12:30:26
"In this case, will the server convert to its local time or will save 11AM and 8AM?"

If the Application includes the time with the Date that it sends to SQL server then that is exactly what SQL Server will store. 11AM for the data from Seattle, 8AM for the data from New York.

If the application just sends the Date then the time will still be stored, but will be set to 00:00:00.

If the application sends a record and says "User Current Server Time" - i.e. the equivalent of GetDate() - then SQL Server will store the current server time and ALL records created will be in ascending chronological order**. Then the user has to query using the Server Time - so if the user thinks they saved it at 8AM local time the actual Server Time would be different, and searching for an 8AM record will find nothing (or a different record )

** Note that when the clocks go back you may get times repeated for that hour, and they won't be created in strict chronological order

BUT ... if you ARE storing the time provided by the application (and NOT SQL Server's own time when the record is created) then you probably have other problems of the various PC's clocks being "unreliable" or "not set to the correct current time"
Go to Top of Page

gena_mak
Starting Member

26 Posts

Posted - 2010-02-08 : 13:24:02
Application uses date only with ODBC date wrapper local to web application server and not time so, I guess its fine in that sense. However, the time is used when data is manipulated by stored procedures and functions where I use datetime datatype.

My concern that when I compare dates straight with >= and =<, I can get erronious results as in some cases when time is used to bring up one record over another and I cant have it happened. That is why I use DateDiff(DAY...) function. Now, I see it causes table scan and I need to get away from this method.
Go to Top of Page
    Next Page

- Advertisement -