У меня есть таблица, содержащая около 100 000 статей.
Каждая статья имеет описание.
короткий пример:
Ни у кого нет одинакового формата.
Что я хотел бы сделать, так это извлечь «НОРМУ» из описания.
Итак, я хотел бы получить следующий результат
Microsoft SQL Server Standard (64-разрядная версия) v11.0.7507.2 У меня просто нет прав администратора для изменения COMPATIBILITY_LEVEL
@ouboma, ты не меняешь схему таблицы. Я думаю, просто выберите не требуется менять разрешение COMPATIBILITY_LEVEL. Поправьте меня, я ошибаюсь.
@502_Geek, когда я использую string_split(), я получаю эту ошибку: «STRING_SPLIT» не является распознаваемым именем встроенной функции, которую можно решить, изменив уровень совместимости. чего я действительно не могу сделать!
К вашему сведению, поддержка версии 11 (2012 г.) полностью закончилась почти 2 года назад, @ouboma. Вам действительно нужно как можно скорее получить последнюю и поддерживаемую версию.
Я думаю, вы забыли упомянуть, как следует извлекать эту «Норму». Вы сидите на формате статьи, можно ли предположить, что это всегда EN<пробел>номер<что-то><запятая> или нет и т.д.
Что касается данных, то кажется, что их следует нормализовать еще до того, как они попадут в вашу таблицу. Если разные части DESCRIPTION означают разные вещи, храните их отдельно.
@ThomA Я полностью с тобой согласен. Но я не отвечаю за получение новой версии SQL и не могу контролировать нормализацию данных. Мне придется работать с тем, что у меня есть. Но я с вами полностью согласен!
@siggemannen нет. иногда это EN<пробел>номер<что-то>номер, иногда EN<пробел>номер, иногда EN<что-то>номер<что-то>номер... это действительно варьируется. но EN всегда заглавная и после нее всегда идут цифры.
Так как же узнать, когда значение прекратится, @ouboma. У вас есть одна строка с EN 10277/10 80, откуда вы знаете, что 80 не является частью нужного вам значения?
Похоже, вам нужен список этих значений «НОРМ», а затем вы можете проверить, соответствует ли значение LIKE вашему DESCRIPTION столбцу, поскольку нет шаблона, который можно было бы найти. Или, опять же, исправьте свой дизайн (это настоящее решение).
@ThomA хороший вопрос. Это ВСЕГДА EN + первый набор цифр. Итак, в вашем случае это будет EN 10277/10, второй пробел после EN - это место, где норма заканчивается.
Давайте продолжим обсуждение в чате.


Это может быть подсказка:
SELECT
ARTIKELNR,
CASE
WHEN CHARINDEX('EN ', DESCRIPTION) > 0 THEN
SUBSTRING(DESCRIPTION, CHARINDEX('EN ', DESCRIPTION), PATINDEX('%[0-9/.]%', SUBSTRING(DESCRIPTION, CHARINDEX('EN ', DESCRIPTION), LEN(DESCRIPTION))))
ELSE
''
END AS NORM
FROM
YourTableName
В этом запросе предполагается, что «EN», за которым следуют цифры, точки или косые черты, однозначно идентифицирует начало NORM.
да, но для первой статьи: 104009400031900 он вернул только EN 1 как норму. однако мне нужен EN 10277/10. есть идеи, как этого добиться? Спасибо
Думаю, это может решить вашу проблему %[0-9]+[-/]?[0-9]*%
@502_Geek Не совсем. оба скрипта дают пробел для artikelnr: 105009400068800
В самых последних версиях SQL Server это на самом деле довольно просто благодаря встроенным функциям. ВЫ можете использовать STRING_SPLIT, чтобы разделить значение и убедиться, что вы возвращаете порядковые номера, чтобы вы могли использовать LEAD или LAG для получения следующего/последнего значения с разделителями и фильтрации по вашим значениям EN. Наконец, вы можете использовать TRIM, чтобы удалить конечные запятые:
WITH CTE AS(
SELECT V.ARTIKELNR,
V.DESCRIPTION,
SS.value,
LEAD(SS.value) OVER (PARTITION BY V.ARTIKELNR ORDER BY SS.ordinal) AS NextValue
FROM (VALUES(104009400031900,N'S235JRG2C+C EN 10277/10 80 x 8 mm Blanker Flachstahl'),
(104009800002950,N'Werksattest nach EN 10204'),
(105009400092360,N'EN 10060 Inox Rund Ø 28 mm WNr1.4034 warmgefertigt'),
(105009400068571,N'90 mm WNr1.4404 warmgefertigt, EN 10060, geschmiedet'),
(105009400004420,N'WNr1.4301 Inox Vierkantstahl 6 x 6 mm EN 10278, blankgezogen'),
(105009400008800,N'WNr1.4301 Inox Band geschnitten 25 x 4 mm, Breitentol. 25 m'),
(105009400068600,N'WNr1.4112 Inox Rund 8.00 mm nach EN 10088-3 + A+C+SL, gesch'),
(105009400068700,N'WNr1.4301 Inox Rund 36.00 mm nach EN 10088-3, geschliffen, T'),
(105009400068800,N'WNr1.4104 Inox Rund 25.00 mm nach EN 10088-3, geschliffen, T'),
(105009400010035,N'WNr1.4404 Inox Vierkantstahl 30 x 30 mm, gezogen EN 10278'))V(ARTIKELNR,DESCRIPTION)
CROSS APPLY STRING_SPLIT(V.DESCRIPTION,' ',1) SS)
SELECT C.ARTIKELNR,
TRIM(',' FROM CONCAT_WS(' ',C.value,C.NextValue)) AS Norm
FROM CTE C
WHERE C.value = 'EN';
В 2012 году (напоминаем, в 2022 году это вообще перестало поддерживаться) немного сложнее. Вы можете заменить STRING_SPLIT другим не встроенным разделителем, который возвращает порядковый номер, например DelimitedN4KSplit_LEAD (N4K, поскольку ваши строки выглядят как nvarchar). У вас по-прежнему есть доступ к LEAD, но нет TRIM, поэтому вам придется использовать REPLACE и RTRIM. Это дает вам что-то вроде этого:
WITH CTE AS(
SELECT V.ARTIKELNR,
V.DESCRIPTION,
DS.item,
LEAD(DS.Item) OVER (PARTITION BY V.ARTIKELNR ORDER BY DS.ItemNumber) AS nextitem
FROM (VALUES(104009400031900,N'S235JRG2C+C EN 10277/10 80 x 8 mm Blanker Flachstahl'),
(104009800002950,N'Werksattest nach EN 10204'),
(105009400092360,N'EN 10060 Inox Rund Ø 28 mm WNr1.4034 warmgefertigt'),
(105009400068571,N'90 mm WNr1.4404 warmgefertigt, EN 10060, geschmiedet'),
(105009400004420,N'WNr1.4301 Inox Vierkantstahl 6 x 6 mm EN 10278, blankgezogen'),
(105009400008800,N'WNr1.4301 Inox Band geschnitten 25 x 4 mm, Breitentol. 25 m'),
(105009400068600,N'WNr1.4112 Inox Rund 8.00 mm nach EN 10088-3 + A+C+SL, gesch'),
(105009400068700,N'WNr1.4301 Inox Rund 36.00 mm nach EN 10088-3, geschliffen, T'),
(105009400068800,N'WNr1.4104 Inox Rund 25.00 mm nach EN 10088-3, geschliffen, T'),
(105009400010035,N'WNr1.4404 Inox Vierkantstahl 30 x 30 mm, gezogen EN 10278'))V(ARTIKELNR,DESCRIPTION)
CROSS APPLY fn.DelimitedSplitN4K_LEAD(V.DESCRIPTION,' ') DS)
SELECT C.ARTIKELNR,
RTRIM(REPLACE(CONCAT(C.item,' ',C.nextitem),',',' ')) AS Norm
FROM CTE C
WHERE C.item = 'EN';
спасибо, но DelimitedN4KSplit_LEAD не поддерживается
Что значит «не поддерживается», @ouboma? ВЫ сказали, что используете SQL Server v11.0.7507.2, то есть 2012 года выпуска; DelimitedN4KSplit_LEAD работает в 2012 году. Совместимость вашей базы данных ниже, чем 110?
Если вы используете более низкий уровень совместимости, @ouboma, вы можете использовать DelimitedSpitN4k, если ваш уровень 100. Если он 90 или ниже, вам действительно нужно поговорить со своим администратором базы данных; это уровни совместимости SQL Server 2005! Вам также следовало упомянуть в вопросе, что мы были ограничены совместимостью с SQL Server 2005; некоторые люди больше не имеют доступа к такой среде.
совместимость базы данных — 110, но когда я запускаю ваш код, первая ошибка, которую я получаю: «CONCAT_WS» не распознается как имя интегрированной функции.
Ага, я почему-то думал, что CONCAT_WS был добавлен в 2012 году, это был 2017 год. Ну, тогда просто переключись на CONCAT, @ouboma ; это несложное изменение (я надеялся, что вы с этим справитесь).
тогда я получаю эту ошибку: Недопустимое имя объекта «fn.DelimitedSplitN4K_LEAD».
Значит, ты еще не создал объект, @ouboma ; эта ошибка говорит вам о проблеме.
Попробуйте следующее решение, использующее функции SQL Server XML и XQuery.
Он будет работать, начиная с SQL Server 2012.
Примечательные моменты:
CROSS APPLY токенизирует столбец DESCRIPTION как XML..query() ищет токен «EN» с помощью выражения FLWOR и следующий токен с помощью предиката XPath ...r[position()=($pos, $pos + 1)]..value() дает нам желаемую выходную строку.REPLACE() удаляет необязательную конечную запятую.SQL
-- DDL and sample data population, start
DECLARE @tbl TABLE (ID INT IDENTITY PRIMARY KEY, ARTIKELNR CHAR(15), DESCRIPTION NVARCHAR(1024));
INSERT INTO @tbl (ARTIKELNR, DESCRIPTION) VALUES
(104009400031770,N'725528 MOTORKONSOLE KM35 EN SENKKLAPPFENSTER WICSKY 3'), -- Exception case, no digits after EN
(104009400031900,N'S235JRG2C+C EN10088-3 80 x 8 mm Blanker Flachstahl'), -- Exception case, no space after EN
(104009400031900,N'S235JRG2C+C EN 10277/10 80 x 8 mm Blanker Flachstahl'),
(104009800002950,N'Werksattest nach EN 10204'),
(105009400092360,N'EN 10060 Inox Rund Ø 28 mm WNr1.4034 warmgefertigt'),
(105009400068571,N'90 mm WNr1.4404 warmgefertigt, EN 10060, geschmiedet'),
(105009400004420,N'WNr1.4301 Inox Vierkantstahl 6 x 6 mm EN 10278, blankgezogen'),
(105009400008800,N'WNr1.4301 Inox Band geschnitten 25 x 4 mm, Breitentol. 25 m'),
(105009400068600,N'WNr1.4112 Inox Rund 8.00 mm nach EN 10088-3 + A+C+SL, gesch'),
(105009400068700,N'WNr1.4301 Inox Rund 36.00 mm nach EN 10088-3, geschliffen, T'),
(105009400068800,N'WNr1.4104 Inox Rund 25.00 mm nach EN 10088-3, geschliffen, T'),
(105009400010035,N'WNr1.4404 Inox Vierkantstahl 30 x 30 mm, gezogen EN 10278');
-- DDL and sample data population, end
DECLARE @separator CHAR(1) = SPACE(1);
SELECT *
, REPLACE(c.query('
for $x in /root/r[text() = "EN"]
let $pos := count(root/r[. << $x]) + 1
return if (xs:int(substring((/root/r[$pos + 1]/text())[1],1,5)) instance of xs:int) then
data(/root/r[position()=($pos, $pos + 1)])
else data(/root/r[$pos])
').value('text()[1]', 'NVARCHAR(30)')
,',', '') AS NORM
FROM @tbl AS t
CROSS APPLY (SELECT PATINDEX('%EN[0-9][0-9][0-9][0-9][0-9]%', DESCRIPTION)) AS t2(pos) -- to handle Exception cases
CROSS APPLY (SELECT TRY_CAST('<root><r><![CDATA[' +
REPLACE(IIF(pos > 0, STUFF(DESCRIPTION,pos + 2,0, SPACE(1)), DESCRIPTION), @separator, ']]></r><r><![CDATA[') +
--REPLACE(DESCRIPTION, @separator, ']]></r><r><![CDATA[') +
']]></r></root>' AS XML)) AS t1(c)
ORDER BY ID;
Выход
и снова здравствуйте. если у меня есть описание типа: (725528 MOTORKONSOLE KM35 EN SENKKLAPPFENSTER WICSKY 3), результатом будет (EN SENKKLAPPFENSTER), что неверно, есть ли обходной путь для этого? ценить это!
Каким будет правильный результат для такого сценария?
это должно быть только EN. Меня интересует только EN, за которым следуют несколько цифр.
Я скорректировал ответ. Проверьте это.
Он проверяет первые 5 символов как цифры в следующем токене.
Я протестировал несколько случаев, и все работает отлично. Если что-то появится, я сообщу вам. Кроме того, знаете ли вы какой-нибудь учебник или веб-сайт, на котором объясняется этот метод корня, значения и запроса? интересно исследовать! еще раз спасибо.
Итак, начнем: Learn.microsoft.com/en-us/sql/xquery/…
Также, пожалуйста, проголосуйте за мое предложение в Microsoft: Feedback.azure.com/d365community/idea/…
какую систему sql и какую версию вы используете?