views:

37

answers:

2

Hello,

I have the following SQL query:

SELECT DISTINCT ProductNumber, PageNumber FROM table

I am trying to modify the query so that PageNumber will be formatted. You see, PageNumber is in any of the following formats, where 'x' is a digit:

  • xxx, xxx
  • xxx
  • xxx-xxx
  • xx, xxx-xxx
  • xx-xx, xxx
  • xx-xx, xxx-xxx

I want to format PageNumber so that it is only in the format: xxx. To do so, I have parse out the following bolded numbers from the above formats:

  • xxx, xxx
  • xxx
  • xxx-xxx
  • xx, xxx-xxx
  • xx-xx, xxx
  • xx-xx, xxx-xxx

I want to do this all without writing any functions, but I don't know if that is possible. I am having trouble "detecting" all of the different formats, though:

Here is what I have so far:

SELECT  ProductNumber,
        CASE WHEN CHARINDEX(',', PageNumber) > 0
             THEN SUBSTRING(PageNumber, 0, CHARINDEX('-', PageNumber))
             WHEN CHARINDEX('-', PageNumber) > 0
             THEN SUBSTRING(PageNumber, 0, CHARINDEX('-', PageNumber))
             ELSE PageNumber
        END AS PageNumber
FROM    table
WHERE   PageNumber IS NOT NULL
    AND PageNumber <> '' 

Can anyone offer me some help? Thanks!

+3  A: 

Use pattern matching rather than CHARINDEX

CASE also forces ordering of evaluation which helps here for the 3rd case which overlaps with the first 2 cases.

Not tested, something like

CASE
    WHEN PageNumber LIKE '[0-9][0-9][0-9]%' THEN LEFT(PageNumber, 3)
    WHEN PageNumber LIKE '[0-9][0-9]-[0-9][0-9], [0-9][0-9][0-9]') THEN RIGHT(PageNumber , 3)
    WHEN PageNumber LIKE '[0-9][0-9]%') THEN LEFT(PageNumber, 2)
END
gbn
Excellent answer, +1
ajdams
doesn't work, syntax fails: Incorrect syntax near ')'. what if the data is `xxxx` or `xxxx-xxxx`, you'll only get first 3 digits.
KM
@KM, just remove the parentheses before the THEN in the second WHEN.
nathan gonzalez
@nathan gonzalez, and the 3rd WHEN as well. Syntax issues aside, there will need to be many WHENs to make this work, and order is important, the first one can't be the first one in the example code.
KM
I had no idea about this, thank you very much. This was perfect for me.
behrk2
@KM: I did say "not tested" and it works for OP's given sample data. 4 digits where not specified... if there were 2, 3, 4, 5,6, 7... digits I'd have used CHARINDEX for that. But CASE/LIKE is cleaner for the given set of data
gbn
+2  A: 

try this:

DECLARE @YourTable table (ProductNumber int, PageNumber varchar(20))
INSERT @YourTable VALUES (1,'123, 456')
INSERT @YourTable VALUES (2,'123')
INSERT @YourTable VALUES (3,'123-456')
INSERT @YourTable VALUES (4,'12, 345-678')
INSERT @YourTable VALUES (5,'12-34, 567')
INSERT @YourTable VALUES (6,'12-34, 567-789')

;WITH AllNumbers AS   ---builds a Numbers table 1-100
(   SELECT 1 AS Number
    UNION ALL
    SELECT Number+1
        FROM AllNumbers
        WHERE Number<101
)
, RowChars AS --one row for each non-numeric single character value per @YourTable row
(   SELECT DISTINCT
        ProductNumber,Number, SUBSTRING(PageNumber,Number,1) AS CharacterOF
        FROM @YourTable
            INNER JOIN AllNumbers  ON 1=1
        WHERE SUBSTRING(PageNumber,Number,1) IS NOT NULL AND SUBSTRING(PageNumber,Number,1) NOT LIKE '[0-9]' AND SUBSTRING(PageNumber,Number,1)!=''
)
,FirstSplit AS --get first non-numeric single character value per @YourTable row
(   SELECT
        ProductNumber,MIN(Number) AS SplitOf
        FROM RowChars
        GROUP BY ProductNumber
)
SELECT
    t.ProductNumber, LEFT(t.PageNumber,COALESCE(s.SplitOf-1,LEN(t.PageNumber))) AS NewPage,t.PageNumber AS OldPage
    FROM @YourTable                 t
        LEFT OUTER JOIN FirstSplit  s ON t.ProductNumber=s.ProductNumber

OUTPUT:

ProductNumber NewPage              OldPage
------------- -------------------- --------------------
1             123                  123, 456
2             123                  123
3             123                  123-456
4             12                   12, 345-678
5             12                   12-34, 567
6             12                   12-34, 567-789

(6 row(s) affected)
KM
Thank you for putting the time into this. While the pattern matching is sufficient for me, I am saving your solution to look at in more depth as it looks like there is more that I can do with it. Thanks!
behrk2