Как заменить несколько символов в Access SQL? - PullRequest
1 голос
/ 14 апреля 2009

Я новичок в SQL, так что, надеюсь, кто-то может объяснить это для меня. Я попытался выполнить публикацию «Заменить несколько строк в SQL-запросе», но застрял.

Я пытаюсь сделать то же самое, что и создатель вышеуказанной публикации, но с другой таблицей и другими полями. Допустим, следующее поле "ShiptoPlant" в таблице "BTST" содержит три записи (в моей таблице тысячи записей) ...

Название таблицы: BTST

   ---------------
   | ShiptoPlant |
   | ----------- |
   | Plant #1    |
   | Plant - 2   |
   | Plant/3     |
   ---------------

Вот что я пытаюсь набрать на экране SQL:

SELECT CASE WHEN ShipToPlant IN ("#", "-", "/") Then ""
ELSE ShipToPlant END FROM BTST;

Я продолжаю получать сообщение (Ошибка 3075) ...

"Syntax error (missing operator) in query expression 
'CASE WHEN ShiptoPlant IN (";","/"," ") Then "" ELSE ShipToPlant END'."

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

Любая помощь, которую вы можете оказать, будет принята с благодарностью!

РЕДАКТИРОВАТЬ: Справочная информация добавлена ​​из комментариев

Я собрал данные на уровне накладных по отдельным позициям от каждого из наших 14 поставщиков за 2008 календарный год. Я пытаюсь нормализовать названия заводов, которые нам дают наши поставщики.

Каждый поставщик может называть завод другим именем, например,

Служба Signode в нашем основном списке могут вызываться поставщиками

Signode Service 
Signode - Service.
SignodeSvc
SignodeService

Я пытаюсь удалить не алфавитно-цифровые символы, чтобы попытаться идентифицировать растение с помощью нашего основного списка, создав серию ссылок, которые просматривают первые 10 символов, если совпадений нет, 8 символов, 6, 4 ...

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

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

UPDATE BTST SET ShipToPlant = replace(ShipToPlant," ","");

РЕДАКТИРОВАТЬ 2: Дополнительная информация взята из комментариев

Каждый месяц до 100 новых комбинаций названий наших заводов появляются в наших данных счета-фактуры для отдельной позиции - это может представлять тысячи записей счета-фактуры. Я пытаюсь создать быстрый и грязный способ присвоения master_id окончательного имени для каждой перестановки имен растений. Лучший способ увидеть это - посмотреть на поля завода, адреса, города и штата, но проблема в том, что эти поля также имеют различные перестановки, например,

128 Brookview Drive
128 Brookview Lane

Вынимая буквенно-цифровые символы и делая

LEFT(PlantName,#chars) & _
LEFT(Address,#chars) & _
LEFT(City,#chars) & _
LEFT(State,#chars) 

и, изменяя количество символов до тех пор, пока не будет найдено соответствие между данными счета-фактуры и списком мастер-растений (обе таблицы содержат поля «Завод», «Адрес», «Город» и «Штат»), вы можете в конечном итоге найти соответствие. Конечно, когда вы начинаете сокращать количество символов, которые вы LEFT набираете, точность снижается. Я сделал это в Excel и имел приличный доход. Кто-нибудь может порекомендовать лучшее решение?

Ответы [ 9 ]

8 голосов
/ 15 апреля 2009

Возможно, вы захотите рассмотреть пользовательскую функцию (UDF)

SELECT ShiptoPlant, CleanString([ShiptoPlant]) AS Clean
FROM Table


Function CleanString(strText)
Dim objRegEx As Object

Set objRegEx = CreateObject("VBScript.RegExp")
objRegEx.IgnoreCase = True
objRegEx.Global = True

objRegEx.Pattern = "[^a-z0-9]"
CleanString = objRegEx.Replace(strText, "")

End Function
4 голосов
/ 14 апреля 2009

Вы можете использовать встроенную функцию Replace в Access

SELECT
    Replace(Replace(Replace(ShipToPlant, "#", ""), "-", ""), "/", "") AS ShipToPlant
FROM
    BTST

Как уже говорили другие, в Access вы можете написать свои собственные функции в VBA и использовать их в своих запросах.

EDIT:

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

Public Function SuperReplace(ByRef field As String, ByVal ReplaceString As String) As String
    ' Size this as big as you need... it is zero-based by default' 
    Dim ReplaceArray(3) As String

    'Fill each element with the character you need to replace'  
    ReplaceArray(0) = "#"
    ReplaceArray(1) = "-"
    ReplaceArray(2) = "/"
    ReplaceArray(3) = " "

    Dim i As Integer
    For i = LBound(ReplaceArray) To UBound(ReplaceArray)    
       field = Replace(field, ReplaceArray(i), ReplaceString)
    Next i

    SuperReplace = field    
End Function

Затем протестируйте его с помощью этого запроса

SELECT 
    SuperReplace(ShipToPlant,"") AS ShipToPlant
FROM
    BTST

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

РЕДАКТИРОВАТЬ 2:

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

Начнем с создания еще одной таблицы, назовем ее plant_map

CREATE TABLE plant_map (id AUTOINCREMENT PRIMARY KEY, name TEXT, master_id LONG)

в plant_map, добавьте все перестановки для имен растений и вставьте идентификатор для имени, которое вы хотите использовать для ссылки на конкретную группу перестановок имен растений, в поле master_id. Из ваших комментариев я буду использовать Signode Service

INSERT INTO plant_map(name, master_id) VALUES ("Signode Service", 1);
INSERT INTO plant_map(name, master_id) VALUES ("Signode Svc", 1);
INSERT INTO plant_map(name, master_id) VALUES ("Signode - Service", 1);
INSERT INTO plant_map(name, master_id) VALUES ("Signode svc", 1);
INSERT INTO plant_map(name, master_id) VALUES ("SignodeService", 1);

Теперь, когда вы запрашиваете таблицу BTST, вы можете получить данные для Служба кодирования , используя

SELECT
    field1,
    field2
FROM
    BTST source
INNER JOIN
    (
    plant_map map1      
    INNER JOIN
    plant_map map2
    ON map1.master_id = map2.id
    )
    ON source.ShipToPlant = map1.name
WHERE
    map2.name = "Signode Service"

Данные в таблице BTST могут остаться без изменений.

По сути, это соединение имени завода в BTST с именем в plant_map, затем, используя master_id, самостоятельное соединение в id в plant_map, так что вам нужно передать только один "общий " название. Я бы посоветовал поставить индекс для каждого из столбцов name и master_id в plant_map, так как оба поля будут использоваться в соединениях.

2 голосов
/ 14 апреля 2009

Не думаю, что Access поддерживает оператор CASE. Рассмотрите возможность использования iif:

iif ( condition, value_if_true, value_if_false )

Для этого случая вы можете использовать функцию ЗАМЕНА:

SELECT 
    REPLACE(REPLACE(REPLACE(yourfield, '#', ''), '-', ''), '/', '') 
    as FieldName
FROM
    ....
1 голос
/ 14 апреля 2009

Создание общедоступной функции в модуле кода.

Public Function StripChars(ByVal pStringtoStrip As Variant, ByVal pCharsToKeep As String) As String

Dim sChar As String
Dim sTemp As String
Dim iCtr As Integer

  sTemp = ""

  For iCtr = 1 To Len(pStringtoStrip)
    sChar = Mid(pStringtoStrip, iCtr, 1)
    If InStr(pCharsToKeep, sChar) > 0 Then
      sTemp = sTemp & sChar
    End If
  Next

  StripChars = sTemp

End Function

Тогда в вашем запросе

SELECT
    StripChars(ShipToPlant, "abcdefghijklmnopqrstuvwxyz0123456789") AS ShipToPlantDisplay  
FROM 
    BTST

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

РЕДАКТИРОВАТЬ: сделать обновление:

UPDATE BTST
    SET ShipToPlant = StripChars(ShipToPlant, "abcdefghijklmnopqrstuvwxyz0123456789")
1 голос
/ 14 апреля 2009

ОК, ваш вопрос изменился, поэтому решение тоже будет. Вот два способа сделать это. Быстрый и грязный способ только частично решит вашу проблему, потому что он не сможет учесть более странные перестановки, такие как пропущенные пробелы или слова с ошибками. Быстрый и грязный способ:

  1. Создайте новую таблицу - назовем ее TCHAR.
  2. Поместите в него текстовое поле - символ (ы), которые вы хотите заменить - мы будем назовите это char для этого примера
  3. Поместите в эту таблицу все комбинации символов или символов, которые вы хотите удалить.
  4. Создайте и выполните запрос ниже. Обратите внимание, что он удалит только один элемент за один раз, но вы также можете положить разные версии одного и того же замена в нем тоже как '-' или '-' Для этого примера я создал таблицу с именем tPlant с полем с именем ShipToPlant.

    SELECT tPlant.ShipToPlant, Replace([ShipToPlant], (SELECT top 1 char FROM tChar WHERE instr(ShipToPlant,char)<>0 ORDER BY len(char) Desc),"" ) AS New FROM tPlant;

Лучший (но гораздо более сложный) способ. Это объяснение будет общим, потому что было бы почти невозможно поместить все это сюда. Если вы хотите связаться со мной напрямую, используйте мое имя пользователя на gmail .:

  1. Создать таблицу квалификаторов - ошибки, которые люди вводят как SVC вместо обслуживания. Здесь вы бы введите каждую странную перестановку, которую вы получить.
  2. Создать таблицу с QualifierID и Идентификатор завода. Здесь вы бы сказали, какие на какой завод идет классификатор.
  3. Создать запрос, который объединяет два и твой столик с ошибочным растением имена в нем. Используй instr так скажи что в полях.
  4. Создайте второй запрос, который усугубляет первое. Посчитать Поле INSTR и использовать его в качестве оценки. Запись с наибольшим количеством очков завод.
  5. Вам придется вручную ввести те, это не может найти, но довольно скоро не будет рядом, как у вас все больше и больше записей в таблице.

Ughh


У вас есть несколько вариантов. В Access нет CASE в sql, вам нужно использовать IIF. Он не так элегантен, как решения в более надежных механизмах БД, и его нужно вкладывать для этого экземпляра, но он сделает работу за вас.

SELECT
    iif(instr(ShipToPlant,"#")<>0,"",
    iif(instr(ShipToPlant,"-")<>0,"",
    iif(instr(ShipToPlant,"/")<>0,"",ShipToPlant ))) AS FieldName
FROM BTST;

Вы также можете сделать это, используя sql для ограничения ваших данных.

SELECT YourID, nz(aBTST.ShipToPlant,"") AS ShipToPlant  
FROM BTST LEFT JOIN (
    SELECT YourID, ShipToPlant 
    FROM BTST 
    WHERE ShipToPlant NOT IN("#", "-", "/")
    ) as aBTST ON BTST.YourID=aBTST.YourID

Если вы знаете VB, вы также можете создавать свои собственные функции и помещать их в запросы ... но это уже другой пост. :) НТН

0 голосов
/ 20 мая 2019

Этот запрос захватывает 3 первых символа и заменяет их пробелами

Пример: BO-1234
Выход: 1234

BO: IIf(IsNumeric(Left([sMessageDetails],3)),[sMessageDetails],Replace([sMessageDetails],Left([sMessageDetails],3),""))
0 голосов
/ 14 сентября 2015

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

Поле, которое я хочу обновить, называется «Клиенты». В поле 'CustName' есть 20 с лишним акцентированных символов, для которых я хочу удалить диакритические знаки - так (например) ã> a.

Для каждого из этих символов я создал новую таблицу 'recodes' с 2 полями 'char' и 'recode'. 'char' содержит символ, который я хочу удалить, а 'перекодировать' содержит замену.

Затем для замены я сделал полное внешнее соединение внутри оператора обновления

UPDATE Customers, Recodes SET Customers.CustName = Replace([CustName],[char],[recode]);

Это имеет тот же эффект, что и вложенность всех операторов замены, и намного проще в управлении.

0 голосов
/ 17 апреля 2009

Все - я вложил функцию REPLACE () в два отдельных запроса. Поскольку мне нужно заменить более 35 не буквенно-цифровых символов, а Access ограничивает сложность запроса до 20 вложенных функций, я просто разделил его на два процесса. Несколько неуклюже, но это сработало. Должен был следовать принципу KISS в этом случае. Спасибо за вашу помощь!

0 голосов
/ 14 апреля 2009

SELECT 
IIF
(
    Instr(1,ShipToPlant , "#") > 0 
    OR Instr(1,ShipToPlant , "/") > 0 
    OR Instr(1,ShipToPlant , "-") > 0, ""
    , ShipToPlant 
)
FROM BTST

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...