2014-12-31 2 views
0

Я пытаюсь получить информацию о продуктах, имеющих идентификатор, содержащийся в списке. Проблема заключается в том, что список содержит несколько отдельных значений и некоторые значения диапазона:SQL: итерирование по списку, который содержит некоторые диапазоны

PX03 - PX069, PX20, PX202, PX25 - PX270, PX250 - PX2509, PX251, PX2511 - PX2513

В основном то, что я ищу, - это какой-то способ взять список или строку, содержащую оба значения и диапазоны, а конечный вывод - это таблица или список, который имеет все значения в пределах диапазонов индивидуально, чтобы я мог их пропустить.

У меня есть хранимая процедура, которая проходит через все идентификаторы в таблице основных продуктов, которые используют префикс «PX», но таблица имеет все идентификаторы (то есть PX 1 - 9999, LX 00001 - 99999), и я хочу только для поиска по содержащимся в приведенном выше списке. Я мог бы написать все индивидуальные идентификаторы, но некоторые из диапазонов содержат много значений, которые потребуют много времени для прохождения.

Моя идея состояла в том, чтобы создать отдельную таблицу, содержащую этот список, в которой будет три столбца: столбец идентичности, а затем один столбец для начала и конца диапазона. Любые предметы, которые не имеют диапазон только бы иметь такое же значение для начала и конца диапазона, то есть:

---------------------------------- 
rownum | range_start | range_end| 
---------------------------------- 
1  PX03   PX069 
2  PX20   PX20 
3  PX202  PX202 
4  PX25   PX25 
5  PX250  PX2509 

, а затем заполнение таблицы, используя что-то вроде:

SELECT id from product_table 
WHERE id BETWEEN listtable.range_start AND listtable.range_end 

где product_table мой оригинал таблица с идентификатором продукта и их информацией и списком - новая таблица, которую я только что создал. Это дало бы мне:

id| 
--- 
PX03 
PX030 
PX031 
PX032 
PX033 
. 
. 
. 
PX067 
PX068 
PX069 
PX20 
PX202 
PX25 
PX250 
PX251 

т.д.

, но я имею в виду, я должен был бы итерацию по списку, и я не знаю, как сделать это. Любые идеи, подсказки или предложения?

UPDATE

После создания таблицы с помощью решения, данное @asantaballa, это было так же просто, как с помощью внутреннего соединения:

SELECT d.id 
FROM product_table d 
INNER JOIN @RangeTable r 
ON d.id BETWEEN r.RangeFrom AND r.RangeTo 
+0

Вы просто пытаетесь получить строки для продуктов, где их идентификатор находится в наборе Идентификаторы? Или ваш главный вопрос об превращении этого списка в набор идентификаторов? – ryanyuyu

+0

@ryanyuyu, вот что я пытаюсь сделать, но там, где есть диапазон, я хочу получить все значения в диапазоне. Это не числовой диапазон, поле ** varchar ** –

+0

Будьте осторожны при использовании 'BETWEEN' для текстовых диапазонов. Например, значение 'PX260' ** не ** между текстовым диапазоном:' PX250-PX2509' –

ответ

0

Смотрите, если это работает для вас части о преобразование строки в таблицу.

Declare @StrList Varchar(1000) = 'PX03 - PX069, PX20, PX202, PX25 - PX270, PX250 - PX2509, PX251, PX2511 - PX2513' 
Declare @RangeTable Table (RangeFrom VarChar(32), RangeTo VarChar(32)) 
Select @StrList = Replace(@StrList,' ', '') + ',' 
Declare @StrListItem Varchar(32) 
While CHARINDEX(',', @StrList) > 0 
Begin 
    Select @StrListItem = SUBSTRING(@StrList,1,CHARINDEX(',', @StrList) - 1) 
    Declare 
     @RangeFrom VarChar(32) 
    , @RangeTo VarChar(32) 
    If CHARINDEX('-', @StrListItem) = 0 
    Begin 
     Select 
      @RangeFrom = @StrListItem 
     , @RangeTo = @StrListItem 
    End 
    Else 
    Begin 
     Select 
      @RangeFrom = SUBSTRING(@StrListItem, 1, CHARINDEX('-', @StrListItem) - 1) 
     , @RangeTo = SUBSTRING(@StrListItem, CHARINDEX('-', @StrListItem) + 1, LEN(@StrListItem) - CHARINDEX('-', @StrListItem)) 
    End 
    Insert Into @RangeTable (RangeFrom, RangeTo) Values (@RangeFrom, @RangeTo) 
    Select @StrList = SUBSTRING(@StrList, CHARINDEX(',', @StrList) + 1, LEN(@StrList) - CHARINDEX(',', @StrList)) 
End 
Select * From @RangeTable 
+0

Спасибо @asantaballa, это очень полезно для создания таблицы. Я сейчас работаю над созданием процесса, возможно, используя вложенный курсор, который будет проходить через мою исходную таблицу идентификаторов и найти все значения, которые лежат в пределах значений диапазона в созданной таблице. –

0

Вот ваш string и product_table

DECLARE @STR VARCHAR(100) = 'PX03 - PX069, PX20, PX202, PX25 - PX270, PX250 - PX2509, PX251, PX2511 - PX2513' 

SELECT * INTO #product_table 
FROM 
(
    SELECT 'PX4' PRODID 
    UNION ALL 
    SELECT 'PX26' 
    UNION ALL 
    SELECT 'PX75' 
    UNION ALL 
    SELECT 'PX77' 
)TAB 

Теперь создать таблицу для хранения значения

CREATE TABLE #listtable(ROWNUM int IDENTITY(1,1),range_start VARCHAR(100),range_end VARCHAR(100)) 

Теперь вставьте расщепляется значение в таблице.

INSERT INTO #listtable 
SELECT 
ISNULL(PARSENAME(REPLACE(Split.a.value('.', 'VARCHAR(100)'),'-','.'),2),Split.a.value('.', 'VARCHAR(100)')) 'range_start' , 
PARSENAME(REPLACE(Split.a.value('.', 'VARCHAR(100)'),'-','.'),1) 'range_end' 
FROM 
(
    SELECT CAST ('<M>' + REPLACE(@STR, ',', '</M><M>') + '</M>' AS XML) AS Data  
) AS A 
CROSS APPLY Data.nodes ('/M') AS Split(a) 

enter image description here

Поскольку Id является строка, вам нужна функция для извлечения числа из Id (функции, созданной Богом из SQL Server - Pinal Dave)

CREATE FUNCTION dbo.udf_GetNumeric 
(@strAlphaNumeric VARCHAR(256)) 
RETURNS VARCHAR(256) 
AS 
BEGIN 
DECLARE @intAlpha INT 
SET @intAlpha = PATINDEX('%[^0-9]%', @strAlphaNumeric) 
BEGIN 
WHILE @intAlpha > 0 
BEGIN 
SET @strAlphaNumeric = STUFF(@strAlphaNumeric, @intAlpha, 1, '') 
SET @intAlpha = PATINDEX('%[^0-9]%', @strAlphaNumeric) 
END 
END 
RETURN ISNULL(@strAlphaNumeric,0) 
END 

Прежде всего держать в помните, что мы не получим PX1,PX2,PX3,PX4, если вы дадите id BETWEEN listtable.range_start AND listtable.range_end, так как они имеют размер varchar, а не numbers. Поэтому нам нужно извлечь числа из каждого PX и получить значения между ними и добавить PX.

enter image description here

Вот запрос, который фильтрует идентификаторы в product_table, которые находятся в диапазоне между listtable

;WITH CTE AS 
(
    SELECT ROWNUM,CAST(dbo.udf_GetNumeric(range_start)AS INT) NUMBERS, 
    CAST(dbo.udf_GetNumeric(range_end)AS INT) RTO1 
    FROM #listtable 
    UNION ALL 
    SELECT T.ROWNUM,NUMBERS+1,RTO1 
    FROM #listtable T 
    JOIN CTE ON CTE.ROWNUM = T.ROWNUM 
    WHERE NUMBERS < RTO1 
) 
SELECT PRODID IDS--,ROWNUM,NUMBERS NUMS,'PX'+CAST(NUMBERS AS VARCHAR(10)) IDS2 
FROM CTE 
JOIN #product_table ON PRODID='PX'+CAST(NUMBERS AS VARCHAR(10)) 
ORDER BY NUMBERS 
option (MaxRecursion 0) 
+0

В этом примере PX05 отсутствует в списке, но находится между PX03 и PX069, где ROWNUM равно 1. Когда PX05 находится в product_table, вы хотите показать PX05, поскольку PX05 находится между PX03 и PX069 (ROWNUM = 1)? @Sam cd –

+0

Я бы хотел, чтобы все значения (из другой таблицы) находились между столбцами range_start и range_end, которые необходимо включить. Я не думаю, что есть необходимость в функции GetNumeric, поскольку значения, которые я заказываю, находятся в ** varchar ** –

+0

Я обновил. Пожалуйста, проверьте @Sam cd –

Смежные вопросы