Posts
83
Comments
600
Trackbacks
40
June 2005 Entries
Once I'm done processing files, How can I archive them?

The following stored procedure will take a supplied file path, create an archive folder within the supplied folder path, and move everything in to that folder to basically clear out the base folder.  The Archive folder gets tagged with the date and time of the operation.  The stored procedure uses code for the Dir procedure I wrote earlier.  In that link there is DDL for the table that is referenced in this sproc. Thanks for reading.

CREATE PROC Archive(@path varchar(2000))
AS
SET NOCOUNT ON
  BEGIN
 DECLARE @cmd varchar(4000), @today varchar(25), @archive varchar(2000)

 EXEC Dir @path, 1

 IF NOT EXISTS(SELECT * FROM Directory_Contents WHERE Dir = @path)
   BEGIN
  PRINT 'No directory was found for ' + @path
  GOTO Archive_Error
   END

 IF NOT EXISTS(SELECT * FROM Directory_Contents WHERE Dir = @path AND Struct_Type = 'FILE')
   BEGIN
  PRINT 'No files in directory ' + @path + ' to Archive'
  GOTO Archive_Error
   END

 SELECT @today = REPLACE(REPLACE(REPLACE(CONVERT(varchar(25),GetDate(),120),' ','_'),':','_'),'-','_')
 SELECT @archive =  + SUBSTRING(@path,1,1+LEN(@path)-CHARINDEX('\',REVERSE(@path))) + 'Archive' + '_' + @today
 SELECT @cmd = 'md "'+ @archive + '"'
 
 EXEC master..xp_cmdshell @cmd
 
  SELECT @cmd = 'move "' + @path + '" "' + @archive + '\"'
 EXEC master..xp_cmdshell @cmd

 Archive_Exit:
  SET NOCOUNT OFF
  RETURN

 Archive_Error:
  -- Add any additional Error Handling
  GOTO Archive_Exit
  END
GO

 

posted @ Thursday, June 30, 2005 3:40 PM | Feedback (9)
How do I use the DOS Command dir in T-SQL

Well, the short answer is you don't.  The modified answer is that you can use the code listed in this post. The longer answer is that you can use xp_cmdshell to do this (Which is what the stored procedure in this post does),  and must be either a member of the sysadmin account, or granted execution, say to a new role, and users can be placed in that role. 

There is a caveat to that.  From Books Online:

Execute permissions for xp_cmdshell default to members of the sysadmin fixed server role, but can be granted to other users.

Important  If you choose to use a Windows NT account that is not a member of the local administrator's group for the MSSQLServer service, users who are not members of the sysadmin fixed server role cannot execute xp_cmdshell.

Also, the long and short of it is, that having to build it, then to parse out the data, and to worry about security measures, I thought it might be a good idea just to create a stored procedure.  Now I'm sure someone may have done this already, but I thought I'd give it a shot.  This makes looking at your directories as easy as issuing the command EXEC Dir 'C:\*.*'.  Well you say, why not just do EXEC xp_cmdshell 'Dir C:\*.*'. Well for one, you won't have to grant your developers access to xp_cmdshell, so you gain more control.  A developer could reak havoc with your server. I've seen it.  Also, the information is now in a usable format.  Your developers can now call this stored procedure and place the results in to a table, or, (since it's all done with smoke and mirrors), they can access the underlying directory table.   As an afterthought, there are several commands that can be turned in to this type of functionality, and you can specialize them to “extend“ dos commands.  Currently I'm working on an archiving sproc that will make an archive directory for a directory supplied.  The idea is that when I'm done with all the files in my processing directory, I will move everything to the archive, so as to clean out the directory for the next processing cycle.  I'll post that when it's done.

One additional caveat is that this is Windows 2000 Server and up.  Windows NT produced different ouput results from the dir dos command.  If you need the old structure, let me know and I can post it.   I know there's away around this, I'm just not sure at the moment on how to do this.  If anyone remembers, I'd like to know.  Again thanks for reading.

 Here's the code, and good luck. 

CREATE TABLE [dbo].[Directory_Contents_Stage] (
   [dir]  varchar(255)
 , [dir_output]  varchar(255)
)
GO

CREATE TABLE [dbo].[Directory_Contents] (
   [dir]  varchar(255)
 , [Create_Time] datetime
 , [File_Size]  int
 , [File_Name]  varchar(255)
 , [Struct_Type] char(9)
)
GO

CREATE PROC Dir(@path varchar(2000), @Supress int = 0)
AS

SET NOCOUNT ON
TRUNCATE TABLE Directory_Contents_Stage

    DECLARE @cmd varchar(4000)
     SELECT @cmd = 'Dir "' + @path + '"'

INSERT INTO Directory_Contents_Stage(dir_output) EXEC master..xp_cmdshell @cmd

  IF EXISTS (SELECT * FROM Directory_Contents_Stage
       WHERE dir_output = 'The system cannot find the file specified.')
    BEGIN
         PRINT 'The system cannot find the file specified.'
         GOTO Dir_Error
    END

  IF EXISTS (SELECT * FROM Directory_Contents_Stage
       WHERE dir_output = 'File Not Found')
    BEGIN
         PRINT 'File Not Found'
         GOTO Dir_Error
    END         

  IF EXISTS (SELECT * FROM Directory_Contents_Stage
       WHERE dir_output = 'The system cannot find the path specified.')
    BEGIN
         PRINT 'The system cannot find the path specified.'
         GOTO Dir_Error
    END

     UPDATE Directory_Contents_Stage SET [dir] = @path

DELETE FROM Directory_Contents WHERE [dir] = @path

INSERT INTO Directory_Contents (Create_Time, File_Size, [File_Name], [dir], [Struct_Type])
     SELECT   CONVERT(datetime,SUBSTRING(dir_output,1,20)) AS [Create_Time]
     , CONVERT(int,LTRIM(RTRIM(REPLACE(SUBSTRING(dir_output,21,19),',','')))) AS [File_Size]
     , SUBSTRING(dir_output,40,(LEN(dir_output)-39)) AS [File_Name]
     , [dir]
     , 'FILE'
      FROM  Directory_Contents_Stage
     WHERE  SUBSTRING(dir_output,1,1) <> ' '
       AND (SUBSTRING(dir_output,1,1) <> ' '
       AND  SUBSTRING(dir_output,25,5) <> CHAR(60)+'Dir'+CHAR(62))

INSERT INTO Directory_Contents (Create_Time, [File_Name], [dir], [Struct_Type])
     SELECT   CONVERT(datetime,SUBSTRING(dir_output,1,20)) AS [Create_Time]
     , SUBSTRING(dir_output,40,(LEN(dir_output)-39)) As [File_Name]
     , [dir]
     , CHAR(60)+'Dir'+CHAR(62) AS  [Struct_Type]
       FROM  Directory_Contents_Stage
      WHERE  SUBSTRING(dir_output,25,5) = CHAR(60)+'Dir'+CHAR(62)

IF @Supress = 0

  SELECT [dir], Create_Time, File_Size, [File_Name], [Struct_Type]
    FROM Directory_Contents
   WHERE [dir] = @path
ORDER BY [Struct_Type] DESC, [Create_Time] DESC
GO

SET NOCOUNT OFF

Dir_Exit:
SET NOCOUNT OFF
RETURN

Dir_Error:
-- Add Error Handling
GOTO Dir_Exit
GO


EXEC Dir 'C:\*.*'
GO

DROP PROC Dir
GO

DROP TABLE Directory_Contents, Directory_Contents_Stage
GO

 

 

posted @ Tuesday, June 28, 2005 10:33 AM | Feedback (13)
Extract Just Numbers from a String

I guess you could modify this to Extract whatever you want.  Here's the thread with the original question. Now I'm not gonna say this is real effecient, but I thought it was a little clever.  Can anyone come up with a full blow set based solution?  I'm sure it'd be ok for an overnight batch process, or used in conjunction with bcp and QUERYOUT, then just bcp.  Now I didn't ask why anyone would need to do this.  I wonder if it was a homework question.  I didn't think to ask, I just got caught up with the challenge.  And I can use all the number table exercises I can get.

 

EDIT: Well, all I can say is that it helps to read these thing.  TG, already posted the correct answer in that thread.  Mea Culpa.

USE Northwind
GO

SET NOCOUNT ON
CREATE TABLE numbers(n int ,[CHAR] char(1))
GO

DECLARE @n int
SET NOCOUNT ON
SELECT @n = 48
WHILE @n < 58
  BEGIN
 INSERT INTO numbers(n, [CHAR]) SELECT @n, CHAR(@n)
 SELECT @n = @n + 1
  END
GO

CREATE FUNCTION udf_x(@x varchar(8000))
RETURNS varchar(8000)
AS
  BEGIN
 DECLARE @n int, @MAX_n int, @z varchar(8000)
 DECLARE @y  table(pos int, value char(1))
 SELECT @MAX_n = LEN(@x), @n = 1, @z = ''
 WHILE @N<
=@MAX_n
   BEGIN
  INSERT INTO @y(pos,value) SELECT @n, SUBSTRING(@x,@n,1)
  SELECT @n = @n + 1
   END
 SELECT @z = @z + [CHAR] FROM @y JOIN numbers ON [CHAR] = value ORDER BY pos
  RETURN @z
  END
GO

SELECT dbo.udf_x('123 Main Apt 456')
GO

SELECT dbo.udf_x(ShipAddress) FROM Orders
GO

SET NOCOUNT OFF
DROP TABLE numbers
DROP FUNCTION udf_x
GO

posted @ Wednesday, June 22, 2005 5:05 PM | Feedback (3)
How do I add many rows of Data using 1 Stored Procedure

Seems this question comes up quite a bit, as it did here.  And then since my boss also was asking me how this is done, I'd figure that I'd post a solution.  It involves forming a comma delimeted string and passing that in to the stored procedure.  Modifying a Bill Graziano User Defined Function, we simply pass in this comma delimeted string.  Now I solved the posters (mester) based on the original Requirements, but I do take exception to the table structures.  They indicate they have a Reseller table, and Company table, and a Junction Table.  While this may be the correct logical model, I would think I would eliminate the juction table.  Kinda like a Person Table, and a Phone Table.  Why bother with a PersonPhone Table.  What would be the sense.  Is it worth the effort to maintain that, or to try enforce RI?  If we make that assumption and lose the junction table, then the cursor in the code below is replaced with a very nice set based insert into the child table.  Clear as mud?  Here's the code sample, and Thanks again Bill (I had to modify my ThankyouBillCounter from int to bigint).

I'd appreciate any Pro's Cons about this approach, and any thoughts you may have.  Thanks for reading

PS I used IDENTITY here because it makes it a little more dicey.  What, no IDENTITY you say?  Then your job just got easier, and to reiterate, with out the juction table, it really easy.

USE Northwind
GO

SET NOCOUNT ON
CREATE TABLE Reseller(
   R_ID int IDENTITY(1,1) PRIMARY KEY
 , R_Detail varchar(50))
CREATE TABLE Company(
   C_ID int IDENTITY(1,1) PRIMARY KEY
 , C_Detail varchar(50))
GO

CREATE TABLE Reseller_Company (
   R_ID int
 , C_ID int
 , CONSTRAINT Company_Reseller_PK  PRIMARY KEY (R_ID, C_ID)
 , CONSTRAINT Company_Reseller_FK1 FOREIGN KEY (R_ID) REFERENCES Reseller (R_ID)
 , CONSTRAINT Company_Reseller_FK2 FOREIGN KEY (C_ID) REFERENCES Company  (C_ID)
)
GO

CREATE FUNCTION dbo.CSVToParse (
 @Array varchar(8000)
)
RETURNS @ParseTable table
 (ParseValue varchar(50))
AS

-- Code Originally (CSVTOint) Written by Bill Graziano, 10/13/2002
--
http://www.sqlteam.com/item.asp?ItemID=11499

  BEGIN
 DECLARE @separator char(1), @separator_position int, @array_value varchar(1000)
  SELECT @separator = ',', @array = @array + ','
 
 WHILE patindex('%,%' , @array) <> 0
   BEGIN
    SET @separator_position =  patindex('%,%' , @array)
   SET @array_value = left(@array, @separator_position - 1)
  INSERT @ParseTable(ParseValue) VALUES (@array_value)
    SET @array = stuff(@array, 1, @separator_position, '')
   END
 RETURN
  END
GO

CREATE PROC usp_INS_Company_Resellers (
   @R_Detail varchar(50)
 , @C_Details varchar(1000)
)
AS
SET NOCOUNT ON
 DECLARE @R_SCOPE_IDENTITY int, @C_SCOPE_IDENTITY int, @C_Detail varchar(50)

 INSERT INTO Reseller(r_Detail) SELECT @R_Detail 
 SELECT @R_SCOPE_IDENTITY = SCOPE_IDENTITY()

 DECLARE Companies CURSOR FOR SELECT ParseValue FROM dbo.CSVToParse(@C_Details)
 OPEN Companies 
 FETCH NEXT FROM Companies INTO @C_Detail
 WHILE @@FETCH_STATUS = 0
   BEGIN

   INSERT INTO Company(C_Detail) SELECT @C_Detail
  SELECT @C_SCOPE_IDENTITY = SCOPE_IDENTITY()

  INSERT INTO Reseller_Company (R_ID, C_ID) SELECT @R_SCOPE_IDENTITY, @C_SCOPE_IDENTITY 
  FETCH NEXT FROM Companies INTO @C_Detail
   END
 CLOSE Companies
 DEALLOCATE Companies
SET NOCOUNT OFF
GO

EXEC [dbo].[usp_INS_Company_Resellers] 'Reseller name...whatever','Company1,Company2,Companty3'
GO

SELECT * FROM Reseller
SELECT * FROM Company
SELECT * FROM Reseller_Company
GO
 
SET NOCOUNT ON
DROP FUNCTION CSVToParse
DROP PROC usp_INS_Company_Resellers
DROP TABLE Reseller_Company, Reseller, Company
GO

 

posted @ Wednesday, June 22, 2005 1:28 PM | Feedback (0)
Ghost records.....ooooooo....scary

OK, Gotta admit to being floored by this.

First I would like to know how many people have heard of this.

Second I would like to go on to describe what this is, how it happens, and how your Ghosts are exorcised.  I guess there truely is a Ghost in the Machine.

When rows are marked as deleted after a DML operation and the transaction is committed, the rows become Ghost records.  Now in DB2, it doesn't care and if the page is mark deleted it will just reuse the page.  Not so in SQL Server.  I was amazed (and shocked) by the fact that there is a background process, the ghost exorciser, that goes on to search for these Ghosts and then does a physical delete (I think).  When Pat Phelan original pointed this out in his thread  he was having trouble where a 3rd party application was not taking care of the ghosts on a particular server.  We then descended in to a discussion of Trace Flags (again another WTF, I never heard of this before...or really only in passing) and didn't find much about them in documentation or books (well I must admit as of this writing I have not search SQL Team yet).  In the thread Pat goes on to show some trace flags that where used to identify these things. 

We were then joined by Paul Randal, who is the Dev Lead for Microsoft SQL Server Storage Engine.  The discussion turned to the trace flags as a potential cause of the problem.  There is actually a trace flag that will turn off the ghost exorciser.  Why anyone would want to do that, I have no idea, but it certainly looked like Pat's problem. Paul's comment “There are lots of (potentially scary) undocumented, or little-understood behaviors one could monitor in SQL Server, but unless its causing a problem, its best to be just understood and left alone.” sounded like good advice to me.  I will never ceased to be amazed at what 3rd party vendors come up with, when they can't tackle to root cause of a problem.  In most cases (read all) it's been becuase of bad database design or implementation.

Why SQL Server does not just reuse a page marked as deleted, I do not know.  I mean why incur the overhead of this excorsism process?

Anyway, the geek really came out in me today.  I was very excited to read about the internal process of SQL server, read about trace flags, to know about them as a potential place to look when thing just don't make sense on someone elses box, and to have a conversation with the guy who built the damn thing.

Yes, this was a good day.

Thanks for reading

Brett 

PS. As to not to regurgatate everything that was said in the thread, and to not parrot everything like I know what the He11 I'm talking about,  I suggest you give it a read

posted @ Tuesday, June 21, 2005 1:21 PM | Feedback (7)
Database Design based on existing data

I really like to avoid doing database design based on existing data structures.  I really prefer to start with a functional flow of the business, target the data (be it existing electronic data, memo;s, post it's, whatever, data is data) for each function, organize all the data across functions into general entities, then take all of the data elemets or attributes and associate them with the higher level Entities.  From all of this, I then would form a logical data model, develop a data dictionary and present it to the the Clients for accuracy.  Then worry about the physical implementation.

BUT!  Sometimes that's not possible.  BUT! Good Normalization rules still apply.  In this post, macca asked a question. that based on an existing data file, how would you build a database.  Since there are 34 unique “Things” should they build that many tables?  Well, in my opinion, the answer was no.  It should be 1 table (as we find out later though, it's really 2).  The interesting part about this problem was the normalization of the data and the code that breaks it up into it's normalized componenets.

How data ends up so denormalized in the first place always suprises me. I mean I understand X400 directory structures and the like as an original “slick” pre XML days to tag data, but it's gonna be really hard for me to accept this, or to accept XML.  I just don't see how it beats the relational model.  I mean how dynamic do you need to be?

In any case, this problem caused me more time than usual to provide the poster a solution, so I figured I'd post it.  Hey Thursday was a foggy day.  Knocked it off this morning in relative short order, but Thursday I just couldn't “see” it.  Kinda like smashing your face on to your desk over and over...anyway....enjoy

USE Northwind
GO

SET NOCOUNT ON
CREATE TABLE myStage99(RowNum int IDENTITY(1,1), col1 varchar(8000))
GO

INSERT INTO myStage99(Col1)
SELECT 'one/a/001, one/a/002, one/a/500' UNION ALL
SELECT 'one/b/001, one/b/002, one/b/500' UNION ALL
SELECT 'one/c/001, one/c/002, one/c/500' UNION ALL
SELECT 'one/d/001, one/d/002, one/d/500' UNION ALL
SELECT 'one/e/001, one/e/002, one/e/500' UNION ALL
SELECT 'one/f/001, one/f/002, one/f/500' UNION ALL
SELECT 'two/a/001, two/a/002, two/a/500' UNION ALL
SELECT 'two/b/001, two/b/002, two/b/500' UNION ALL
SELECT 'two/f/001, two/f/002, two/f/500' UNION ALL
SELECT 'seven/a/001, seven/a/002, seven/a/500' UNION ALL
SELECT 'seven/b/001, seven/b/002, seven/b/500' UNION ALL
SELECT 'seven/f/001, seven/f/002, seven/f/500'
GO

CREATE TABLE mySection_SubSection99([Section] varchar(20), SubSection char(1), SubSectionNum char(3))
GO

DECLARE   @RowNum int, @MAX_RowNum int, @s int, @e int, @col1 varchar(8000), @parse varchar(24)
 , @Section varchar(20), @SubSection char(1), @SubSectionNum char(3)

SELECT @RowNum = 1, @MAX_RowNum = MAX(RowNum), @s = 1, @e = 1 FROM myStage99

WHILE @RowNum <= @MAX_RowNum
  BEGIN
 SELECT @Col1 = Col1 FROM myStage99 WHERE RowNum = @RowNum
 SELECT @e = CHARINDEX(',',Col1,@s)-1 FROM myStage99 WHERE RowNum = @RowNum
 WHILE @e > -1
   BEGIN
  SELECT @Parse = SUBSTRING(Col1, @s, @e-@s+1) FROM myStage99 WHERE RowNum = @RowNum
  
  INSERT INTO mySection_SubSection99([Section], SubSection, SubSectionNum)
  SELECT    SUBSTRING(@Parse,1,CHARINDEX('/',@Parse)-1) AS [Section]
   , SUBSTRING(@Parse,CHARINDEX('/',@Parse)+1,1) AS SubSection
   , RIGHT(@Parse,3) AS SubSectionNum

  SELECT @s = @e + 3
  SELECT @e = CHARINDEX(',',Col1,@s)-1 FROM myStage99 WHERE RowNum = @RowNum
   END

 SELECT @Parse = REVERSE(SUBSTRING(REVERSE(Col1), 1, CHARINDEX(',',REVERSE(Col1))-2))
   FROM myStage99 WHERE RowNum = @RowNum

 INSERT INTO mySection_SubSection99([Section], SubSection, SubSectionNum)
 SELECT    SUBSTRING(@Parse,1,CHARINDEX('/',@Parse)-1) AS [Section]
  , SUBSTRING(@Parse,CHARINDEX('/',@Parse)+1,1) AS SubSection
  , RIGHT(@Parse,3) AS SubSectionNum

 SELECT @RowNum = @RowNum + 1, @s = 1, @e = 1
  END
GO

CREATE TABLE [dbo].[mySection99] (
 [Section] [varchar] (20) NOT NULL PRIMARY KEY
) ON [PRIMARY]
GO

INSERT INTO mySection99([Section])
SELECT DISTINCT [Section] FROM mySection_SubSection99
GO

ALTER TABLE dbo.mySection_SubSection99 ADD CONSTRAINT
 FK_mySection_SubSection99_mySection99 FOREIGN KEY
 (
 [Section]
 ) REFERENCES dbo.mySection99
 (
 [Section]
 )
GO

SELECT * FROM mySection99
GO

SELECT * FROM mySection_SubSection99
GO

DROP TABLE myStage99
DROP TABLE mySection_SubSection99
DROP TABLE mySection99
GO

 

posted @ Monday, June 13, 2005 10:38 AM | Feedback (0)
SUBSTRING with Delimiters

I've been having to parse DB2 Load Cards and to extract a lot of data (Like starting postion, Length, Column name, ect) you need parse the data out of the card based on delimiters.  DB2 pretty much is consistent as to were the data resides in it's offsets to certain keywords.  Anyway instead of using strat and Length, I figured I could make a substring function that uses “delimiters”

CREATE FUNCTION SUBSTRING_DEL(
 @Col varchar(8000), @s varchar(1000), @e varchar(1000)
)
RETURNS varchar(8000)
AS
  BEGIN
 DECLARE @rs varchar(8000)
 SELECT @rs = SUBSTRING( @Col
     , CHARINDEX(@s,@col)+LEN(@s)
     , ((CHARINDEX(@e,@Col,CHARINDEX(@s,@Col)+LEN(@s))) - (CHARINDEX(@s,@Col)+LEN(@s))))
 Return LTRIM(RTRIM(@rs))
  END
GO

Here's a sample line as to what a line in the DB2 Control Card looks like

DECLARE @x varchar(80)
SELECT  @x = ' PERSON_ID                              POSITION(       1         )'
SELECT    LTRIM(RTRIM(SUBSTRING(@x,2,18)))     AS COLUMN_NAME
 , CONVERT(int,dbo.SUBSTRING_DEL(@x,'POSITION(',')')) AS StartingPosition

 

EDIT: I'm trying to change this

RowNum      Mnemonic Card                                                                            
----------- -------- --------------------------------------------------------------------------------
1           T0000090   LOAD DATA LOG NO INDDN SYSREC00 INTO TABLE                                   
2           T0000090       AXBB72DA.PERS_TELE_ALL                                                   
3           T0000090    (                                                                           
4           T0000090    PERSON_ID                              POSITION(       1         )          
5           T0000090    CHAR(                     12) ,                                             
6           T0000090    ID_TYPE_CD                             POSITION(      13         )          
7           T0000090    CHAR(                      3) ,                                             
8           T0000090    ASSOC_TYPE_CD                          POSITION(      16         )          
9           T0000090    CHAR(                      5) ,                                             
10          T0000090    STATUS_CD                              POSITION(      21         )          
11          T0000090    CHAR(                      1) ,                                             
12          T0000090    LAST_NAME                              POSITION(      22         )
          
13          T0000090    CHAR(                     20) ,                                     

 

Into this

 

rowNum      Mnemonic COLUMN_NAME        StartingPosition Length     
----------- -------- ------------------ ---------------- -----------
4           T0000090 PERSON_ID          1                12
6           T0000090 ID_TYPE_CD         13               3
8           T0000090 ASSOC_TYPE_CD      16               5
10          T0000090 STATUS_CD          21               1
12          T0000090 LAST_NAME          22               20

 

And was done using

SELECT a.rowNum, a.Mnemonic, a.COLUMN_NAME, a.StartingPosition, b.Length
FROM (
 SELECT    RowNum, Mnemonic
  , LTRIM(RTRIM(SUBSTRING(l.Card,2,18)))     AS COLUMN_NAME
  , CONVERT(int,dbo.SUBSTRING_DEL(l.Card,'POSITION(',')')) AS StartingPosition
   FROM CTLCards l
  WHERE l.Card LIKE '%POSITION%'
) AS a
JOIN (
 SELECT    r.RowNum, l.Mnemonic
  , LTRIM(RTRIM(SUBSTRING(r.Card,2,18)))    AS COLUMN_NAME
  , CONVERT(int,dbo.SUBSTRING_DEL(l.Card,'(',')')) AS Length
   FROM CTLCards l JOIN CTLCards r ON l.RowNum = (r.RowNum + 1)
  WHERE l.Card LIKE '%CHAR(%'
) AS b
ON a.RowNum = b.RowNum

 

posted @ Wednesday, June 08, 2005 12:32 PM | Feedback (1)
Fun with Dates (Date Conversion examples)

No!  Not that kind of fun with your date.  It seems lately a lot of Date conversion questions have been popping up.  So I'd thought I'd list them all here with their solutions and the author that has supplied them.  I will be adding to this list, everytime we come across other date manipulation requests.

1. If I only have the week and Year how do I displayJAN, FEB, MAR, ect Asked by Chandra78.

I suggested:

DECLARE @week int, @year int
SELECT @week = 23, @year = 2005

SELECT CONVERT(char(3)
 ,DATEADD(ww,@week-1
   ,CONVERT(datetime,'01/01/'+CONVERT(char(4),@Year)
   )
 ),100)

2. How Do I get the last day of the Month.  Was Asked by AskSQLTeam (as well as many others in the past)

Rob and Corey offer their suggestions as:

There's Just a slight type-o in Rob's post in the thread...he was missing the trailing parenthesis

DECLARE @datecol datetime
SELECT @datecol = '06/01/2005'
SELECT DateAdd(day,-1,DateAdd(month,DateDiff(month,0,@dateCol)+1,0))

Corey's Solution Appears to be a little simpler

SELECT dateadd(mm,1,@dateCol - day(@dateCol)+1)-1

3. How do I only Get the date portion of a datetime value

Alway the great question.  So much so that M$ decided to put it in SQL Server 2005 as 2 distinct datatypes.  Like every other RDBMS that I've ever worked with.  Unfortunatley it proved too much for the developers, and was pulled from the release.  Jeff, however discuss a work around to date and time isolationism in SQL Server in his blog.  After several thread back and forth (it sometimes is very difficult to asertain what the real question is) was "For example if I wanted to see all data for dates greater or equal to 01/01/2005“.  The short answer From Rob and madhivanan is:

SELECT * FROM myTable WHERE dateCol>='1/1/2005'

 But I suspect the real question to be the comparison of two dates and eliminating the time Componet.  While Jen's Answer with DATDIFF :

SELECT * FROM myTable WHERE datediff(day,@d1,@d2)=0

Does this, I believe it's a stage II (NonSargable) Predicate and will incur a scan.  The question usually is how do I see my Data between these 2 dates.  While this also shows an Index scan, it does mention that it may be a full scan, or only a range, which is what I believe it's doing.

USE Northwind
GO

DECLARE @datecol1 datetime, @datecol2 datetime
SELECT @datecol1 = '1996-09-01', @datecol2 = '1996-09-30'

SELECT *
  FROM Orders
 WHERE OrderDate > @datecol1 AND OrderDate < @datecol2

4. The Counting Days and Excluding Weekend and Holidays recurring question.  I think Nigel was the first time I saw a solution to this problem.  Nigel's Site, has some of the most invaluable stuff you will ever find.

5. Hours Till Margaritaville was a thing I messed around with that counted down the hours until 5:00 Friday.  Enigma (and his Sql Gladiators) however took it to a whole other level in his link.

6. Date of first day of week for current week was just asked recentley by steve_o  and was answered by thombpil.  He suggested:

select dateadd(dd, (datepart(dw, GetDate()) * -1) + 2, GetDate())

7. Win32 FILETIME values.  This is a must entry here.  Arnold came to the rescue that day Almost 2 years ago (man it's been 2 years?).  It's amazing what third party vendors will think up for storing data in SQL Server.  Just painful....I'm not sure if they just wanted to store the data that way, or they thought they were saving space.

SELECT CAST(((
    CAST(CAST(SUBSTRING(@d, 1, 2) AS int) AS float)  * 16777216.0
 +  CAST(CAST(SUBSTRING(@d, 3, 3) AS int) AS float)) * 16777216.0
 +  CAST(CAST(SUBSTRING(@d, 6, 3) AS int) AS float))/ 864000000000.0 - 109207.0 AS datetime)

8. Help: Date in field table and Select condition...well this was just plain silly...As Tara points out 

9. To get first and last day of a week as clboren asks, in their very first SQLTeam post.  Tara suggests the use of a numbers table (which, after many years doing sql I never even thought about before until reading about here at SQL Team) or Michael who employees a user defined function F_START_OF_WEEK.  Thanks again to Tara for pointing this out.  Since is was 6:30 EST, it was way past Margaritaville time (OK, it was on Thursday and I had to coach little league),  and I would have never seen it.

10.  Date as Int ...which seems to be, as Arnold point out as a Wild guess: it's seconds from UNIX epoch.“  Seems to hold true.  We'll keep an eye out if lassew ever comes back to confirm this, BUT Arnolds Formula seems pretty well to hold true.

DECLARE @dok_dt int
SELECT @dok_dt = 1047034683
SELECT DATEADD(s, @dok_dt, '19700101 00:00:00')

11. Start of week Functions by Micheal

12. A very nice background about Dates can be found in this thread by Tibor Karaszi

13. Jeff Smith's very good article in his blog, Date Only and Time Only User Defined Dataypes in SQL Server 2000

14. How do I convert the current date in to a Julian Date?  Assuming ccyyddd

CREATE FUNCTION udf_Julian (
 @d datetime
)
RETURNS varchar(7)
  BEGIN
 RETURN (SELECT CONVERT(char(4),YEAR(@d))+CONVERT(varchar(3),DATEPART(dy,@d)))
  END

SELECT GetDate(), dbo.udf_Julian(GetDate())
GO

15.  How do I create a DB2 Date from SQL Server

Create Function SQLDateToDB2Date(@TargetDate datetime)
returns varchar(30)
as
begin
return replace(replace(convert(varchar(30), @TargetDate, 121),':', '.'), ' ', '.')+'000'
end

16. ...and how do I turn DB2 dates into SQL Server datetime

well you can't really, but you can fake it

DECLARE @x varchar(26)
SELECT @x = '2001-01-01-12:59:59:123456'
SELECT CONVERT(datetime,SUBSTRING(STUFF(@x,11,1,' '),1,23))

17. Stay tuned...more to come I'm sure

 

posted @ Thursday, June 02, 2005 12:07 PM | Feedback (23)