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 2000 Forums
 SQL Server Development (2000)
 Enhancement to "Deleted" record status

Author  Topic 

SamC
White Water Yakist

3467 Posts

Posted - 2006-01-22 : 18:19:56
I've got a column in every user record:

Deleted BIT NOT NULL DEFAULT 0,

But a new requirement to have knowledge of the date of Deletion came up. Something or other about pulling historic reports which include users who were not deleted at that time in history... I need to implement another Column which specifies the "Deleted Date" and phase out the "Deleted BIT" ASAP.

There are two approaches to implementing a Deleted Date column: should and active user have a NULL deleted date or a MAXIMUM VALUE deleted date?

First Case:
DeletedDate SMALLDATETIME NULL DEFAULT NULL,

Second Case"
DeletedDate SMALLDATETIME NOT NULL DEFAULT 'December 31, 9999' -- Defaults to Max SMALLDATETIME value

Here's how I see WHERE clauses would reference the two types of definitions:

First Case:
WHERE @ParmOfDesiredReportingDate < Users.DateDeleted

I struck the where because if Users.DateDeleted is NULL (not deleted), it doesn't return those rows. To return NOT deleted users, plus those users who were deleted at a later time than the report period longer...

WHERE Users.DateDeleted IS NULL OR @ParmOfDesiredReportingDate < Users.DateDeleted

Second Case
WHERE @ParmOfDesiredReportingDate < Users.DateDeleted

The second case WHERE is simpler and preferable (to me) in this case.. The only other test I can see coming is searching for Deleted or NOT Deleted users...

First Case
WHERE Users.DateDeleted IS NULL -- Search for Deleted Users
WHERE Users.DateDeleted IS NOT NULL -- Search for NOT Deleted Users

Second Case
WHERE Users.DateDeleted = 'December 31, 9999' -- Search for Deleted Users
WHERE Users.DateDeleted < 'December 31, 9999' -- Search for NOT Deleted Users

Seems the second case solution is a better overall deal for programming, readability and performance.

Have I overlooked any consideration which would make the first case preferable?

Sam

Footnote: The minimum date can be coded as CASE('' AS SMALLDATETIME)...

Is there any similar method to code the maximum SMALLDATETIME without coding it explicitly as 'Dec 31, 9999'?

SamC
White Water Yakist

3467 Posts

Posted - 2006-01-22 : 20:21:05
smalldatetime max value is 'June 6, 2079', not 'Dec 31 9999'.
Go to Top of Page

khtan
In (Som, Ni, Yak)

17689 Posts

Posted - 2006-01-22 : 20:37:17
quote:
The smalldatetime data type stores dates and times of day with less precision than datetime. SQL Server stores smalldatetime values as two 2-byte integers. The first 2 bytes store the number of days after January 1, 1900. The other 2 bytes store the number of minutes since midnight. Dates range from January 1, 1900, through June 6, 2079, with accuracy to the minute.


select dateadd(day, 0, 65535) as [Max of smalldatetime]

-----------------
'KH'

Go to Top of Page

SamC
White Water Yakist

3467 Posts

Posted - 2006-01-22 : 20:39:44
I noticed that the maximum SMALLDATETIME in binary is 0xFFFF0000 (the 0s are midnight...)

65535 is not much easier to recall than Jun 6 2079, and it's seems more cryptic.
Go to Top of Page

khtan
In (Som, Ni, Yak)

17689 Posts

Posted - 2006-01-22 : 21:56:02
What is your consideration of choosing smalldatetime over datetime ?

For me, I will definately go for datetime. 9999-12-31 and definately easier to understand than 65535 or Jun 6 2079.

On your Deleted Bit & Deleted Date, why you have to phase out the bit. Can't you have both in a table, although there might be an slight overlapping of functionality in there. At least the changes is not that drastic and only Apps / screen that need to display the deleted date will be affected

-----------------
'KH'

Go to Top of Page

Michael Valentine Jones
Yak DBA Kernel (pronounced Colonel)

7020 Posts

Posted - 2006-01-22 : 23:28:25
I don't see the point of coding the not deleted date as 'Dec 31 9999'. Why not just let it be NULL? It seems like a good use for it.

Using 'Dec 31 9999' is just overloading a value. The deleted date doesn't exist, so why put a fake value there?

Especially when someone writes a query like this, and then wonders why so many of the deletions are in December:

select
[Deleted Month] = datename(month,DeletedDate),
count(*)
from
MyTable




CODO ERGO SUM
Go to Top of Page

byrmol
Shed Building SQL Farmer

1591 Posts

Posted - 2006-01-22 : 23:43:04
>>Using 'Dec 31 9999' is just overloading a value.

But at least it's a value. :-)

You could use NULL and then chuck a view around it. Or vice versa! It just depends on what how you want to implement it. Just ensure that the eventual implmentation satifies the logical requirement.

One thing that worries me about this design is that it is a partial solution. What is stoppping someone from flipping the BIT/datetime back to "Active"? You would lose 2 data timepoints...


DavidM

Intelligent Design is NOT science.

A front-end is something that tries to violate a back-end.
Go to Top of Page

SamC
White Water Yakist

3467 Posts

Posted - 2006-01-23 : 00:20:39
quote:
Originally posted by khtan

What is your consideration of choosing smalldatetime over datetime ?
Sam: I can't imagine the importance of tracking the deleted date to a finer granularity than SMALLDATETIME. Give me a good reason to use DATETIME.

For me, I will definately go for datetime. 9999-12-31 and definately easier to understand than 65535 or Jun 6 2079.
Sam: This may be a good enough reason to go with DATETIME over SMALLDATETIME. It's easier to recall the MAX date.

On your Deleted Bit & Deleted Date, why you have to phase out the bit. Can't you have both in a table, although there might be an slight overlapping of functionality in there.
Sam: Ancient Chinese Proverb: Man who wear two Seikos never sure what time it is.



Go to Top of Page

SamC
White Water Yakist

3467 Posts

Posted - 2006-01-23 : 00:29:57
quote:
Originally posted by Michael Valentine Jones

I don't see the point of coding the not deleted date as 'Dec 31 9999'. Why not just let it be NULL?
That's the question I was asking in the first post. It seems easier to test for NOT DELETED users when NULL is not involved. Don't you agree?
quote:
Originally posted by Michael Valentine Jones

Especially when someone writes a query like this, and then wonders why so many of the deletions are in December:

select
[Deleted Month] = datename(month,DeletedDate),
count(*)
from
MyTable


If I were going to argue this, I'd say that query doesn't account for deleted and not deleted users.

To count the deletions in December, I'd write

SELECT DATENAME(month, DeletedDate)
FROM MyTable
WHERE DeletedDate < 'Dec 31 9999' -- All users who are not deleted

This isn't an academic point. Every single reporting procedure I have reports on deleted or NOT deleted, rarely either. There's almost never a query that doesn't check deleted status.

Go to Top of Page

SamC
White Water Yakist

3467 Posts

Posted - 2006-01-23 : 00:33:45
quote:
Originally posted by byrmol

One thing that worries me about this design is that it is a partial solution. What is stoppping someone from flipping the BIT/datetime back to "Active"? You would lose 2 data timepoints...
This must be a good point because I am in denial about it's relevancy.
Go to Top of Page

byrmol
Shed Building SQL Farmer

1591 Posts

Posted - 2006-01-23 : 01:47:01
>>This must be a good point because I am in denial about it's relevancy.

Do you need to know that something was ever deleted? Ie. A row moves from Active->Deleted->Active. The current design misses this scenario.


DavidM

Intelligent Design is NOT science.

A front-end is something that tries to violate a back-end.
Go to Top of Page

Kristen
Test

22859 Posts

Posted - 2006-01-23 : 02:19:38
Where did my post just go to? Out of time to retype it all now ...

1) Use NULL - no difference between "MyDeleteDate IS NULL" and "MyDeleteDate = 2999/12/31"

2a) Retain the MyDeletedBit column so that all your existing code will still work
2b) Create a trigger that sets MyDeletedDate to GetDate if "MyDeletedBit = 1 AND MyDeletedDate IS NULL" and resets it to NULL if "MyDeletedBit = 0 AND MyDeletedDate IS NOT NULL"

3) Just add your new report for "Was not deleted at the time in question" and all existing "Deleted this" and "Is this deleted" logic, based on the old MyDeletedBit, will still work just fine!

Kristen

Go to Top of Page

SamC
White Water Yakist

3467 Posts

Posted - 2006-01-23 : 07:39:57
quote:
Originally posted by byrmol

Do you need to know that something was ever deleted? Ie. A row moves from Active->Deleted->Active. The current design misses this scenario.
Oh Yeah... I completely see the point. My concern is that I don't see the need (today) or forsee the need (tomorrow), but that doesn't meet it won't raise it's ugly head sometime in the future.

For now. creating a stack of deleted dates would complicate queries by adding a JOIN and worse, to the MAX or RANGE Deleted entry.

This fuels the denial, I don't want to believe that it's necessary to stack up historic Delete / Undelete DATETIMEs. I'm 70% sure I'm right, but I have some doubts.
Go to Top of Page

SamC
White Water Yakist

3467 Posts

Posted - 2006-01-23 : 07:47:27
quote:
Originally posted by Kristen

1) Use NULL - no difference between "MyDeleteDate IS NULL" and "MyDeleteDate = 2999/12/31"
Sam: I don't know if I can write:
WHERE MyDeleteDate IS NULL OR MyDeleteDate > @ReportDate -- Requires 2 tests at runtime...

instead of

WHERE MyDeleteDate > @ReportDate -- Ahh! That's much better!

any chance the execution plan would be better on one or the other?


2a) Retain the MyDeletedBit column so that all your existing code will still work
Sam: Yes, but eventually, I'd like to replace all references of MyDeletedBit to use MyDeleteDate. I usually kneejerk away from having the same flag twice anywhere (Ref: the Chinese proverb I posted above?). I'm not sure how or when, but "Murphy's Law" (or is it some other law?) says if I keep both the BIT and DATE that they'll contradict each other some day and I'll be debugging that mess. Then again, I could be over reacting.

2b) Create a trigger that sets MyDeletedDate to GetDate if "MyDeletedBit = 1 AND MyDeletedDate IS NULL" and resets it to NULL if "MyDeletedBit = 0 AND MyDeletedDate IS NOT NULL"
I'll be giving this some consideration. I haven't cast anything in stone.

3) Just add your new report for "Was not deleted at the time in question" and all existing "Deleted this" and "Is this deleted" logic, based on the old MyDeletedBit, will still work just fine!
Sam: Sorry, I wasn't clear, but I've gotta implement this on all reports. In my case, there's a drop-down for historic data... pick the year, do the report. The good news, is it's a migratable solution. I can evolve the reports over time in a non-disruptive way.
Go to Top of Page

jsmith8858
Dr. Cross Join

7423 Posts

Posted - 2006-01-23 : 09:02:32
Sam -- I agree with you about the need for an OR if you use a NULL; it is cleaner to just say "where DeleteDate > @ReportDate".

I haven't tested this to see if there are any weird efficiency drawbacks (there shouldn't be), but one thing you can do is use a UDF to return the constant of "NotDeleted" as whatever date you want:

create function NotDeleted
returns datetime
as
return '99991231'

something like that ... technically, though, I think no one will ever need to know this or use this date ... wouldn't

WHERE DeleteDate > (any date sufficiently in the future, i.e., getdate()+1 )

always return all active rows?
Go to Top of Page

SamC
White Water Yakist

3467 Posts

Posted - 2006-01-23 : 09:19:34
quote:
Originally posted by jsmith8858

I haven't tested this to see if there are any weird efficiency drawbacks (there shouldn't be), but one thing you can do is use a UDF to return the constant of "NotDeleted" as whatever date you want:

I'd never considered using functions to replace the lack of global symbolic constants in SQL. Not a bad idea.

It seems to me the NULL / NOT NULL question on the DeleteDate boils down to minor trade-offs. I see no major weight to tilt the argument to an uncontestable position of either solution.
Go to Top of Page
   

- Advertisement -