June 22, 2011 at 12:10 pm
In case I have numbered items belonging to a group, I would like to be able
to get rows or a single string saying all found range of numbers in the given
set or group.
For instance, when having:
125
226
227
310
351
352
353
Result should be:
125,226-227,310,351-353
Or
125
226 227
310
351 353
Should also run in 2005,
Thanks in advance.
June 22, 2011 at 4:29 pm
your question has no context and is not phrased very well.
If you could explain your question a little clearer, and give some context ( in teh form of an example) you may get more responses. not trying to be nasty, im trying to help you get answers.
June 22, 2011 at 5:01 pm
winston Smith (6/22/2011)
your question has no context and is not phrased very well.If you could explain your question a little clearer, and give some context ( in the form of an example) you may get more responses. not trying to be nasty, im trying to help you get answers.
What winston is saying ... just click on the first link in my signature block and read the article (It also has the T-SQL code) to allow you to post table definition / sample data / expected results from the sample data .. quickly and easily. In that manner you most likely will get a tested answer
In other words help us to help you
June 22, 2011 at 5:36 pm
I agree it's not phrased very well, but if I understand correctly then there's a good answer to a similar question over at the msdn forums : http://social.msdn.microsoft.com/Forums/en-CA/transactsql/thread/c097ff31-aa01-4d7f-a1c4-63d3738ed147.
June 23, 2011 at 1:01 am
Thank you very much SQL Pirate for your response, it's exactly what I was looking for. I'm sorry previous explanation probably was not that clear to all, but Data was clear enought and perfectly technically comprensible.
According to the evaluation whether this is weird or not, said in msdn, it's very usefull to detect for instance wich primary keys are missing, or to simplify a list of items to be checked and save paper..
Thanks a lot again.
June 23, 2011 at 5:54 am
I have been trying to apply the same solution as recommended in the msdn article:
In order to work with alphanumeric islands within a single column, to be able to detect islands or groups of items an put them separated with '-' and put separated isolated values with ','.
For example, in a store with several items having alphanumeric primary key (lets say table Products):
SCREWDRIVER
04738
04739
DRILL400
256
257
258
04740
04741
HAMMER
Return value should be:
256-258,04738-04741,DRILL400,HAMMER,SCREWDRIVER
I could not improve the SQL to do it, could you give some try?
Thanks a lot in advance.
June 23, 2011 at 7:22 am
Try this
DECLARE @Products TABLE(ID VARCHAR(20) NOT NULL PRIMARY KEY)
INSERT INTO @Products(ID)
SELECT 'SCREWDRIVER' UNION ALL
SELECT '04738' UNION ALL
SELECT '04739' UNION ALL
SELECT 'DRILL400' UNION ALL
SELECT '256' UNION ALL
SELECT '257' UNION ALL
SELECT '258' UNION ALL
SELECT '04740' UNION ALL
SELECT '04741' UNION ALL
SELECT 'HAMMER';
WITH CTE AS (
SELECT ID,
ROW_NUMBER() OVER(ORDER BY ID) -
CASE WHEN ID LIKE '%[^0-9]%' THEN NULL ELSE CAST(ID AS INT) END AS rnDiff
FROM @Products)
SELECT STUFF((SELECT ','+MIN(ID)+CASE WHEN MAX(ID)>MIN(ID)
THEN '-'+MAX(ID)
ELSE ''
END AS "text()"
FROM CTE
GROUP BY COALESCE(CAST(rnDiff AS VARCHAR(20)),ID)
ORDER BY MIN(ID)
FOR XML PATH('')),1,1,'') As Results;
____________________________________________________
Deja View - The strange feeling that somewhere, sometime you've optimised this query before
How to get the best help on a forum
http://www.sqlservercentral.com/articles/Best+Practices/61537June 23, 2011 at 9:01 am
Thanks a lot Mark! It works great.
Althought I found out two issues.
First is related to Data:
There are a lot of Alphanumeric PK which are continuous, I'm sorry I did not specified in the first sample data. ie:
DECLARE @Products TABLE(ID VARCHAR(20) NOT NULL PRIMARY KEY)
INSERT INTO @Products(ID)
SELECT 'SCREWDRIVER' UNION ALL
SELECT '04738' UNION ALL
SELECT '04739' UNION ALL
SELECT 'DRILL400' UNION ALL
SELECT 'DRILL401' UNION ALL
SELECT 'DRILL402' UNION ALL
SELECT 'DRILL403' UNION ALL
SELECT '256' UNION ALL
SELECT '257' UNION ALL
SELECT '258' UNION ALL
SELECT '04740' UNION ALL
SELECT '04741' UNION ALL
SELECT 'HAMMER';
Output now is:
04738-04741,256-258,DRILL400,DRILL401,DRILL402,DRILL403,HAMMER,SCREWDRIVER
Optimized output should be:
04738-04741,256-258,DRILL400-DRILL403,HAMMER,SCREWDRIVER
The second issue is for long text results the query returns empty.
Thanks again friend, it was great!
June 23, 2011 at 9:21 am
This may break depending on your data
WITH CTE AS (
SELECT ID,
ROW_NUMBER() OVER(ORDER BY ID) -
-- If there are any alphabetic characters following the numeric characters then this will fail
CASE WHEN ID LIKE '%[0-9]%' THEN CAST(SUBSTRING(ID,PATINDEX('%[0-9]%',ID),LEN(ID)) AS INT) END AS rnDiff
FROM @Products)
SELECT STUFF((SELECT ','+MIN(ID)+CASE WHEN MAX(ID)>MIN(ID)
THEN '-'+MAX(ID)
ELSE ''
END AS "text()"
FROM CTE
GROUP BY COALESCE(CAST(rnDiff AS VARCHAR(20)),ID)
ORDER BY MIN(ID)
FOR XML PATH('')),1,1,'') As Results;
____________________________________________________
Deja View - The strange feeling that somewhere, sometime you've optimised this query before
How to get the best help on a forum
http://www.sqlservercentral.com/articles/Best+Practices/61537June 23, 2011 at 10:12 am
I added a little modification, I eliminated last '%' to indicate I just care final numbers, this works, but it splits groups and create some mess:
DECLARE @Products TABLE(ID VARCHAR(20) NOT NULL PRIMARY KEY)
INSERT INTO @Products(ID)
SELECT 'SCREWDRIVER' UNION ALL
SELECT '04737' UNION ALL
SELECT '04738' UNION ALL
SELECT '04739' UNION ALL
SELECT '04740' UNION ALL
SELECT '04741' UNION ALL
SELECT '3DRILL399' UNION ALL
SELECT '3DRILL400' UNION ALL
SELECT '3DRILL401' UNION ALL
SELECT '3DRILL402' UNION ALL
SELECT '3DRILL403' UNION ALL
SELECT '256' UNION ALL
SELECT '257' UNION ALL
SELECT '258' UNION ALL
SELECT 'HAMMER';
WITH CTE AS (
SELECT ID,
ROW_NUMBER() OVER(ORDER BY ID) -
CASE WHEN ID LIKE '%[0-9]' THEN CAST(SUBSTRING(ID,PATINDEX('%[0-9]',ID),LEN(ID)) AS INT) END AS rnDiff
FROM @Products)
SELECT STUFF((SELECT ','+MIN(ID)+CASE WHEN MAX(ID)>MIN(ID)
THEN '-'+MAX(ID)
ELSE ''
END AS "text()"
FROM CTE
GROUP BY COALESCE(CAST(rnDiff AS VARCHAR(20)),ID)
ORDER BY MIN(ID)
FOR XML PATH('')),1,1,'') As Results;
Output is wrong:
04737-04739,04740-04741,256-3DRILL399,3DRILL400-3DRILL403,HAMMER,SCREWDRIVER
Unfortunatelly data is like that, any idea to solve it?
Thanks a lot again.
June 23, 2011 at 10:35 am
You could probably split the primary key into the leading alphanumeric part and trailing numeric part by searching for the first non-numeric character from the end of the string (use REVERSE). Unfortunately I don't have time to do this now, perhaps someone else can step in?
____________________________________________________
Deja View - The strange feeling that somewhere, sometime you've optimised this query before
How to get the best help on a forum
http://www.sqlservercentral.com/articles/Best+Practices/61537June 24, 2011 at 12:45 am
Good morning Mark, it's DONE!!!.. I'm actually glad! if sometime you need a team, count on me! Please test it when you get some time:
DECLARE @Products TABLE(ID VARCHAR(20) NOT NULL PRIMARY KEY)
INSERT INTO @Products(ID)
SELECT 'SCREWDRIVER' UNION ALL
SELECT '04737' UNION ALL
SELECT '04738' UNION ALL
SELECT '04739' UNION ALL
SELECT '3DRILL399' UNION ALL
SELECT '3DRILL400' UNION ALL
SELECT '3DRILL401' UNION ALL
SELECT '3DRILL402' UNION ALL
SELECT '3DRILL403' UNION ALL
SELECT '3DRILL407' UNION ALL
SELECT '9988' UNION ALL
SELECT '04740' UNION ALL
SELECT '04741' UNION ALL
SELECT '256' UNION ALL
SELECT '257' UNION ALL
SELECT '258' UNION ALL
SELECT 'HAMMER';
WITH CTE AS (
SELECT ID,
ROW_NUMBER() OVER(ORDER BY ID) -
CASE WHEN ID LIKE '%[0-9]' THEN CAST(SUBSTRING(ID,LEN(ID)-PATINDEX('%[0-9]%',REVERSE(ID))-1,LEN(ID)) AS INT) END AS rnDiff
FROM @Products)
SELECT STUFF((SELECT ','+MIN(ID)+CASE WHEN MAX(ID)>MIN(ID)
THEN '-'+MAX(ID)
ELSE ''
END AS "text()"
FROM CTE
GROUP BY COALESCE(CAST(rnDiff AS VARCHAR(20)),ID)
ORDER BY MIN(ID)
FOR XML PATH('')),1,1,'') As Results;
Output is:
04737-04741,256-258,3DRILL399-3DRILL403,3DRILL407,9988,HAMMER,SCREWDRIVER
Best Regards,
L.
June 24, 2011 at 1:51 am
crackbridge (6/24/2011)
Good morning Mark, it's DONE!!!.. I'm actually glad! if sometime you need a team, count on me! Please test it when you get some time:DECLARE @Products TABLE(ID VARCHAR(20) NOT NULL PRIMARY KEY)
INSERT INTO @Products(ID)
SELECT 'SCREWDRIVER' UNION ALL
SELECT '04737' UNION ALL
SELECT '04738' UNION ALL
SELECT '04739' UNION ALL
SELECT '3DRILL399' UNION ALL
SELECT '3DRILL400' UNION ALL
SELECT '3DRILL401' UNION ALL
SELECT '3DRILL402' UNION ALL
SELECT '3DRILL403' UNION ALL
SELECT '3DRILL407' UNION ALL
SELECT '9988' UNION ALL
SELECT '04740' UNION ALL
SELECT '04741' UNION ALL
SELECT '256' UNION ALL
SELECT '257' UNION ALL
SELECT '258' UNION ALL
SELECT 'HAMMER';
WITH CTE AS (
SELECT ID,
ROW_NUMBER() OVER(ORDER BY ID) -
CASE WHEN ID LIKE '%[0-9]' THEN CAST(SUBSTRING(ID,LEN(ID)-PATINDEX('%[0-9]%',REVERSE(ID))-1,LEN(ID)) AS INT) END AS rnDiff
FROM @Products)
SELECT STUFF((SELECT ','+MIN(ID)+CASE WHEN MAX(ID)>MIN(ID)
THEN '-'+MAX(ID)
ELSE ''
END AS "text()"
FROM CTE
GROUP BY COALESCE(CAST(rnDiff AS VARCHAR(20)),ID)
ORDER BY MIN(ID)
FOR XML PATH('')),1,1,'') As Results;
Output is:
04737-04741,256-258,3DRILL399-3DRILL403,3DRILL407,9988,HAMMER,SCREWDRIVER
Best Regards,
L.
Looks good, I think you're sorted now.
____________________________________________________
Deja View - The strange feeling that somewhere, sometime you've optimised this query before
How to get the best help on a forum
http://www.sqlservercentral.com/articles/Best+Practices/61537June 24, 2011 at 8:23 am
Last Release, tested for new cases, see data.
Requires implementation of function: dbo.IsInteger(ID)
Regards!
DECLARE @Products TABLE(ID VARCHAR(20) NOT NULL PRIMARY KEY)
INSERT INTO @Products(ID)
SELECT 'SCREWDRIVER' UNION ALL
SELECT '224537' UNION ALL
SELECT '224538' UNION ALL
SELECT '224539' UNION ALL
SELECT '04737' UNION ALL
SELECT '04738' UNION ALL
SELECT '04739' UNION ALL
SELECT '3DRILL399' UNION ALL
SELECT '3DRILL400' UNION ALL
SELECT '3DRILL401' UNION ALL
SELECT '3DRILL402' UNION ALL
SELECT '3DRILL403' UNION ALL
SELECT '3DRILL409' UNION ALL
SELECT '3DRILL410' UNION ALL
SELECT '3DRILL411' UNION ALL
SELECT '9988' UNION ALL
SELECT '04740' UNION ALL
SELECT '04741' UNION ALL
SELECT '256' UNION ALL
SELECT '257' UNION ALL
SELECT '258' UNION ALL
SELECT 'HAMMER' UNION ALL
SELECT '51T1023-56' UNION ALL
SELECT '51T1023-57' UNION ALL
SELECT '51T1023-58' UNION ALL
SELECT 'FLEX3-6' UNION ALL
SELECT 'FLEX3-7' UNION ALL
SELECT 'FLEX3-8' ;
WITH CTE AS (
SELECT ID,
ROW_NUMBER() OVER(ORDER BY ID) -
CASE
WHEN dbo.IsInteger(ID)=1
THEN CAST(ID AS INT)
WHEN ID LIKE '%[^0-9]%[0-9]' THEN
SUBSTRING(ID,LEN(ID)-PATINDEX('%[^0-9]%',REVERSE(ID))+2,LEN(ID))
END AS rnDiff
FROM @Products)
SELECT STUFF((SELECT ', '+MIN(ID)+CASE WHEN MAX(ID)>MIN(ID)
THEN ' to '+MAX(ID)
ELSE ''
END AS "text()"
FROM CTE
GROUP BY COALESCE(CAST(rnDiff AS VARCHAR(20)),ID)
ORDER BY MIN(ID)
FOR XML PATH('')),1,1,'') As Results;
Viewing 14 posts - 1 through 13 (of 13 total)
You must be logged in to reply to this topic. Login to reply