sql - I am trying to get the start date ONLY from the column below using a SUBSTRING. Can someone tell me what I'm doing

This is what I have so far:DECLARE @STR AS VARCHAR(1000) = 'CustomerID #101010 added. Fixed Price:

This is what I have so far:

DECLARE @STR AS VARCHAR(1000) = 'CustomerID #101010 added. Fixed Price: 3.5555 Effective from 10/16/2024 to 03/31/2 SADFGZFGDA025 Deliveries: 100 Company Pricing Program: TEST 1 Pricing Plan Name: Test plan' 

SELECT 
     CASE 
         WHEN CHARINDEX('Effective from ', @STR) > 0 
              AND CHARINDEX(CHAR(10), @STR, CHARINDEX('Effective from ', @STR)) > 0 
             THEN SUBSTRING(@STR, CHARINDEX('Effective from ', @STR) + LEN('Effective from ') + 1, CHARINDEX(CHAR(10), @STR, CHARINDEX('Effective from ', @STR) + LEN('Effective from ') + 1) - (CHARINDEX('Effective from ', @STR) + LEN('Effective from ') + 1)) 
          WHEN CHARINDEX('Effective from ', @STR) > 0 
              THEN SUBSTRING(@STR,CHARINDEX('Effective from ', @STR) + LEN('Effective from ') + 1, 60) 
          ELSE NULL 
     END 'Start Date'

I'm only trying to see 10/16/2024, so I need the substring to end before the to.

This is what I have so far:

DECLARE @STR AS VARCHAR(1000) = 'CustomerID #101010 added. Fixed Price: 3.5555 Effective from 10/16/2024 to 03/31/2 SADFGZFGDA025 Deliveries: 100 Company Pricing Program: TEST 1 Pricing Plan Name: Test plan' 

SELECT 
     CASE 
         WHEN CHARINDEX('Effective from ', @STR) > 0 
              AND CHARINDEX(CHAR(10), @STR, CHARINDEX('Effective from ', @STR)) > 0 
             THEN SUBSTRING(@STR, CHARINDEX('Effective from ', @STR) + LEN('Effective from ') + 1, CHARINDEX(CHAR(10), @STR, CHARINDEX('Effective from ', @STR) + LEN('Effective from ') + 1) - (CHARINDEX('Effective from ', @STR) + LEN('Effective from ') + 1)) 
          WHEN CHARINDEX('Effective from ', @STR) > 0 
              THEN SUBSTRING(@STR,CHARINDEX('Effective from ', @STR) + LEN('Effective from ') + 1, 60) 
          ELSE NULL 
     END 'Start Date'

I'm only trying to see 10/16/2024, so I need the substring to end before the to.

Share Improve this question edited Nov 19, 2024 at 17:48 Joel Coehoorn 416k114 gold badges578 silver badges813 bronze badges asked Nov 19, 2024 at 15:01 SQL_AliasesSQL_Aliases 15 bronze badges 3
  • 4 Please do not upload images of code/data/errors when asking a question. – Thom A Commented Nov 19, 2024 at 15:10
  • 1 While asking a question, you need to provide a minimal reproducible example: (1) DDL and sample data population, i.e. CREATE table(s) plus INSERT T-SQL statements. (2) What you need to do, i.e. logic and your code attempt implementation of it in T-SQL. (3) Desired output, based on the sample data in the #1 above. (4) Your SQL Server version (SELECT @@version;). All within the question as text, no images. – Yitzhak Khabinsky Commented Nov 19, 2024 at 15:23
  • Question title says "column", but question body is using a single variable... – Yitzhak Khabinsky Commented Nov 19, 2024 at 15:26
Add a comment  | 

4 Answers 4

Reset to default 1

You can reduce the number of repeated expressions by using CROSS APPLY to calculate intermediate results. This allows you to calculate a value once and use it multiple times later in the query. Defining the start and end search strings as variables can also improve readability.

Generalizing the use case to string values coming from a table, the following should achieve your desired results.

DECLARE @StringStart VARCHAR(100) = 'Effective from '
DECLARE @StringStartLen INT = LEN(@StringStart + 'x') - 1 -- True length w/ space
DECLARE @StringEnd1 VARCHAR(100) = ' '
DECLARE @StringEnd2 VARCHAR(100) = CHAR(10)

SELECT D.Str, R.Result
FROM Data D
CROSS APPLY(
    SELECT NULLIF(CHARINDEX(@StringStart, D.Str), 0) + @StringStartLen AS StartPos
) P1
CROSS APPLY (
    SELECT LEAST(
        NULLIF(CHARINDEX(@StringEnd1, D.Str, P1.StartPos), 0),
        NULLIF(CHARINDEX(@StringEnd2, D.Str, P1.StartPos), 0),
        LEN(D.Str) + 1
        ) - P1.StartPos AS Length
) P2
CROSS APPLY (
    SELECT TRY_CAST(SUBSTRING(D.Str, P1.StartPos, P2.Length) AS Date) AS Result
) R

NULLIF() is used to map the no-match 0 result from CHARINDEX() to null, so that non-matches will be ignored.

Another approach is to use PATINDEX() to search for the combined prefix, content, and suffix using a SQL Server LIKE pattern.

DECLARE @StringPattern VARCHAR(100) =
    '%Effective from [0-9][0-9]/[0-9][0-9]/[0-9][0-9][0-9][0-9][ ' + CHAR(10) + ']%'
DECLARE @StringStartOffset INT = 15
DECLARE @ExtractLength INT = 10

SELECT
    D.Str,
    TRY_CAST(SUBSTRING(
        D.Str,
        NULLIF(PATINDEX(@StringPattern, D.Str + ' '), 0) + @StringStartOffset,
        @ExtractLength
        ) AS Date) AS Result
FROM Data D

This assumes that your dates are always of the form "MM/DD/YYYY" with leading zeros. The end of the pattern matches either a space or a newline. To allow end-of-string matching, a space is added to the source string.

The TRY_CAST() also assumes that your dates are compatible with the current SET DATEFORMAT setting. You can alternately use TRY_CONVERT() with an explicit format code (such as 101 or 103) or remove the conversion altogether to just return the text.

Results (with some modified sample data)

Str Result
Case with space - Effective from 10/16/2024 to ... 2024-10-16
Case with newline - Effective from 10/16/2024
more stuff ...
2024-10-16
Case at end of string - Effective from 10/16/2024 2024-10-16
Not matched (: instead of space) - Effective from:10/16/2024 null

See this db<>fiddle for a demo.

Firstly, you have code like

CHARINDEX(CHAR(10), @STR)

In several places. While it (curiously) does not raise an error, that first parameter is not a particularly valid string to search for, so that function call will always return 0. This means your first WHEN Statement will always be ignored.

The second WHEN is structured to start extracting characters from the correct point in the string, but then it reads an arbitrary 60 characters, as opposed to what you actually want.

The following shows one way to extract the desired value. I broke it into two parts for clarity—certainly it could all be munged together into a single statement, but things like this get hard to read very quickly. Note that this does not factor in error handling—it assumes that there will be a valid date there, which I would not count on given the “provided “to” date value shown.

DECLARE @STR AS VARCHAR(1000) = 'CustomerID #101010 added. Fixed Price: 3.5555 Effective from 10/16/2024 to 03/31/2 SADFGZFGDA025 Deliveries: 100 Company Pricing Program: TEST 1 Pricing Plan Name: Test plan' 

DECLARE
  @SubString1     varchar(1000)
 ,@EffectiveFrom  date

--  The string, starting at the date to be extracted
SET @SubString1 = SUBSTRING(@STR, CHARINDEX('Effective from ', @STR) + 15, 1000)

--PRINT @SubString1
--PRINT charindex(' to ', @Substring1)

--  Extract the date
SET @EffectiveFrom = left(@Substring1, charindex(' to ', @Substring1))

PRINT @EffectiveFrom

It really feels like you have overly complicated the problem here. Your date is only 10 characters, so why not just find where the position of the date is, and then get the 10 characters after that? Something like this:

DECLARE @STR AS varchar(1000) = 'CustomerID #101010 added. Fixed Price: 3.5555 Effective from 10/16/2024 to 03/31/2 SADFGZFGDA025 Deliveries: 100 Company Pricing Program: TEST 1 Pricing Plan Name: Test plan';

SELECT SUBSTRING(@STR,NULLIF(CHARINDEX('Effective from',@STR),0)+LEN('Effective from')+1,10);

So I find the position of 'Effective from' (if it's not found, return NULL), add the length of the string 'Effective from'+1, and then return the next 10 characters.

You may, as well, want to wrap the entire expression in a TRY_CONVERT to attempt to convert the value to an actual date value. This also means you don't get completely invalid dates if the text for the "date" is nonsense, such as the "to" date in your example, which is 03/31/2 (and thus not a valid date):

SELECT TRY_CONVERT(date, <expression>, 101);

I am trying to get the start date ONLY from the column below using a SUBSTRING.

Assuming that data resides in the database table column, here is another way to handle it via tokenization through XML and XQuery.

Notable points:

  • CROSS APPLY is tokenizing column data as XML.
  • XPath expression [contains(., "/")][1] is looking for the first data element with a forward slash, i.e. fromDate
  • TRY_CONVERT(DATE,...) is producing fromDate as a real DATE data type.

SQL

-- DDL and sample data population, start
DECLARE @tbl TABLE (id INT IDENTITY PRIMARY KEY, tokens VARCHAR(1000));
INSERT INTO @tbl (tokens) VALUES
('CustomerID #101010 added. Fixed Price: 3.5555 Effective from 10/16/2024 to 03/31/2 SADFGZFGDA025 Deliveries: 100 Company Pricing Program: TEST 1 Pricing Plan Name: Test plan');
-- DDL and sample data population, end

DECLARE @separator CHAR(1) = SPACE(1);

SELECT * 
    , TRY_CONVERT(DATE, c.query('
        for $x in /root/r/text()[contains(., "/")][1]
        return $x
    ').value('.', 'CHAR(10)'), 101) AS startDate
FROM @tbl AS t
CROSS APPLY (SELECT TRY_CAST('<root><r><![CDATA[' + 
      REPLACE(tokens, @separator, ']]></r><r><![CDATA[') + 
      ']]></r></root>' AS XML)) AS t1(c);

Output

id tokens startDate
1 CustomerID #101010 added. Fixed Price: 3.5555 Effective from 10/16/2024 to 03/31/2 SADFGZFGDA025 Deliveries: 100 Company Pricing Program: TEST 1 Pricing Plan Name: Test plan 2024-10-16

发布者:admin,转转请注明出处:http://www.yc00.com/questions/1742420823a4440644.html

相关推荐

发表回复

评论列表(0条)

  • 暂无评论

联系我们

400-800-8888

在线咨询: QQ交谈

邮件:admin@example.com

工作时间:周一至周五,9:30-18:30,节假日休息

关注微信