0

i have this table:

CREATE TABLE MyTable (
    IdDate int,
    FullDate varchar(255)
);

insert into MyTable (IdDate,FullDate)
VALUES (0, 'Nº1 (26) - Friday 4, January 2014'),
       (0,'Nº2 (64) - Monday 10, February 2015')

I wanna extract from FullDate something like this:

1 2014 01 04
2 2015 02 10

1st number is extracted from Nº1
2nd number is extracted from Year
3rd number is extracted from Month (convert January to 01)
4th number is extracted from day (if day < 10, add 0 at the beginning: 01,02... )

And update the new value extracted in first column called IdDate

My final result should be like:

IdDate        FullDate
120140104     Nº1 (26) - Friday 4, January 2014
220150210     Nº2 (64) - Monday 10, February 2015
John Cappelletti
  • 79,615
  • 7
  • 44
  • 66
Raul Escalona
  • 117
  • 1
  • 10

4 Answers4

3

If open to a helper Table-Valued Function:

Example

Declare @YourTable table (IdDate int,FullDate varchar(max))
Insert Into @YourTable values
 (0,'Nº1 (26) - Friday 4, January 2014')
,(0,'Nº2 (64) - Monday 10, February 2015')

Update A
   set IdDate = substring(Pos1,3,10)
              + try_convert(varchar(10),try_convert(date,Pos6+' '+Pos5+' '+Pos7),112)
 From  @YourTable A
 Cross Apply [dbo].[tvf-Str-Parse-Row](FullDate,' ') B

Returns

IDDate      FullDate
120140104   Nº1 (26) - Friday 4, January 2014
220150210   Nº2 (64) - Monday 10, February 2015

If it Helps with the Visualization, the TVF Returns

enter image description here

The Function if Interested

CREATE FUNCTION [dbo].[tvf-Str-Parse-Row] (@String varchar(max),@Delimiter varchar(10))
Returns Table 
As
Return (
    Select Pos1 = ltrim(rtrim(xDim.value('/x[1]','varchar(max)')))
          ,Pos2 = ltrim(rtrim(xDim.value('/x[2]','varchar(max)')))
          ,Pos3 = ltrim(rtrim(xDim.value('/x[3]','varchar(max)')))
          ,Pos4 = ltrim(rtrim(xDim.value('/x[4]','varchar(max)')))
          ,Pos5 = ltrim(rtrim(xDim.value('/x[5]','varchar(max)')))
          ,Pos6 = ltrim(rtrim(xDim.value('/x[6]','varchar(max)')))
          ,Pos7 = ltrim(rtrim(xDim.value('/x[7]','varchar(max)')))
          ,Pos8 = ltrim(rtrim(xDim.value('/x[8]','varchar(max)')))
          ,Pos9 = ltrim(rtrim(xDim.value('/x[9]','varchar(max)')))
    From  (Select Cast('<x>' + replace((Select replace(@String,@Delimiter,'§§Split§§') as [*] For XML Path('')),'§§Split§§','</x><x>')+'</x>' as xml) as xDim) as A 
)

Or Without the Function

Update A
   set IdDate = substring(Pos1,3,10)
              + try_convert(varchar(10),try_convert(date,Pos6+' '+Pos5+' '+Pos7),112)
 From  @YourTable A
 Cross Apply (
                Select Pos1 = ltrim(rtrim(xDim.value('/x[1]','varchar(max)')))
                      ,Pos2 = ltrim(rtrim(xDim.value('/x[2]','varchar(max)')))
                      ,Pos3 = ltrim(rtrim(xDim.value('/x[3]','varchar(max)')))
                      ,Pos4 = ltrim(rtrim(xDim.value('/x[4]','varchar(max)')))
                      ,Pos5 = ltrim(rtrim(xDim.value('/x[5]','varchar(max)')))
                      ,Pos6 = ltrim(rtrim(xDim.value('/x[6]','varchar(max)')))
                      ,Pos7 = ltrim(rtrim(xDim.value('/x[7]','varchar(max)')))
                From  (Select Cast('<x>' + replace((Select replace(FullDate,' ','§§Split§§') as [*] For XML Path('')),'§§Split§§','</x><x>')+'</x>' as xml) as xDim) as A 
             ) B

EDIT

This is an expanded version of Shawn's cleaner solution

Update @YourTable 
   set IdDate = substring(left(FullDate,charindex(' ',FullDate)-1),3,25)
               +try_convert(varchar(10),try_convert(date,replace(substring(FullDate, charindex(',', FullDate) - 2, 100), ',', '')),112)


Select * from @YourTable
John Cappelletti
  • 79,615
  • 7
  • 44
  • 66
2

This will extract a date value. It just looks for the comma, backs up a few characters and grabs the date, strips the comma and treats it as a military date.

select convert(date,  
   replace(substring(FullDate, charindex(',', FullDate) - 2, 100), ',', ''), 106)

Use format() or date style 112 to get the output the way you need. The first character is apparently just substring(FullDate, 3, 1) so just append that to the front.

shawnt00
  • 16,443
  • 3
  • 17
  • 22
1

If you have to wrestle this without using a function like John posted (which is what I would do) you can dig in and start a nightmarish path of string functions. The challenge is that t-sql is not great at string manipulation.

This seems to work on the sample data you provided. Note that if you have data that can't be converted to a date this will fail.

update MyTable
set IdDate = substring(FullDate, 3, CHARINDEX(' ', FullDate) - 3)
    + Right(FullDate, 4)
    + right('0' + convert(varchar(2), datepart(month, convert(date, replace(substring(substring(FullDate, charindex('-', FullDate) + 2, len(FullDate)), charindex(' ', substring(FullDate, charindex('-', FullDate) + 2, len(FullDate))) + 1, len(FullDate)), ',', '')))), 2)
    + right('0' + convert(varchar(2), datepart(day, convert(date, replace(substring(substring(FullDate, charindex('-', FullDate) + 2, len(FullDate)), charindex(' ', substring(FullDate, charindex('-', FullDate) + 2, len(FullDate))) + 1, len(FullDate)), ',', '')))), 2)

select * from MyTable

Then go ask the person who decided to store data like this why they did it? This is not how to handle data at all.

Sean Lange
  • 33,028
  • 3
  • 25
  • 40
  • Error converting a string of characters in the date and / hour. my column FullDate is varchar(255) – Raul Escalona Aug 30 '18 at 16:01
  • You must have some garbage data. It works fine using your sample data and table. – Sean Lange Aug 30 '18 at 16:02
  • When I get the new IdDate, I will remove the column FullDate – Raul Escalona Aug 30 '18 at 16:03
  • Oy!!! You are going to go from one terrible design to another. Stop the insanity!!! This is two pieces of information. A number and a date. Cramming them together is still violating 1NF. Make this into two columns or you will continue to have problems. – Sean Lange Aug 30 '18 at 16:04
0
1st number is extracted from Nº1
2nd number is extracted from Year
3rd number is extracted from Month (convert January to 01)
4th number is extracted from day (if day < 10, add 0 at the beginning: 01,02... )

Use SQL Server's string functions to do the following

  1. Get the characters between and the first blank space that follows it.
  2. Get the last 4 characters
  3. Use a CASE expression to generate a month number based on what month name is LIKE the string
  4. Get the 2 characters before the comma, and replace any blank characters in that with a 0.

And concatenate those 4 values together.

Tab Alleman
  • 31,483
  • 7
  • 36
  • 52
  • But how can i do that? – Raul Escalona Aug 30 '18 at 15:33
  • 1
    https://learn.microsoft.com/en-us/sql/t-sql/functions/string-functions-transact-sql?view=sql-server-2017 (also added to answer). You have asked a broad question and I have given you a broad strategy. Use this link to do some research and make an attempt to solve the problem. If you get stuck on any one of these techniques, make that a new question, so that you can focus your question on one specific technique. – Tab Alleman Aug 30 '18 at 15:37
  • 1
    I disagree Tab. The OP doesn't know what to do. They have provided functional ddl and sample data. It is clear what they expect as output. This data is such a complete trainwreck that it isn't easy to unravel this mess. – Sean Lange Aug 30 '18 at 15:39