1

我是 SQL 的新手,所以希望有人可以为我说明这一点。我尝试按照“替换 SQL 查询中的多个字符串”发布,但我被卡住了。

我正在尝试与上述帖子的发起人做同样的事情,但使用不同的表格和不同的字段。假设下面的字段“ ShiptoPlant”在表“ BTST”中有3条记录(我的表实际上有数千条记录)......

表名: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 中完成了这项工作,并且获得了不错的收益。谁能推荐一个更好的解决方案?

4

9 回答 9

8

您可能希望考虑使用用户定义函数 (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
于 2009-04-14T20:01:10.727 回答
4

您可以使用 Access 中的内置Replace功能

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

正如其他人所说,在 Access 中,您可以在 VBA 中编写自己的函数并在查询中使用它们。

编辑:

这是一种通过将 Replace 函数包装在我们自己的函数中来处理嵌套 Replace 限制的方法。感觉很脏但很管用——把它放在 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中,添加植物名称的所有排列,并将您希望用来引用特定植物名称排列组的名称的 id 插入到 master_id 字段中。根据您的评论,我将使用Signnode 服务

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 表时,您可以使用以下方法获取Signnode服务的数据

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, self 加入id其中,plant_map这样您只需要传入一个“通用”名称。我建议在每个列上放置一个索引,name因为这两个字段都将用于连接。master_idplant_map

于 2009-04-14T18:41:26.220 回答
2

不要认为 Access 支持 CASE 语句。考虑使用 iif:

iif ( condition, value_if_true, value_if_false )

对于这种情况,您可以使用 REPLACE 功能:

SELECT 
    REPLACE(REPLACE(REPLACE(yourfield, '#', ''), '-', ''), '/', '') 
    as FieldName
FROM
    ....
于 2009-04-14T18:26:59.750 回答
1

好的,你的问题已经改变了,所以解决方案也会改变。这里有两种方法。快速而肮脏的方法只能部分解决您的问题,因为它无法解释更奇怪的排列,例如缺少空格或拼写错误的单词。快速而肮脏的方式:

  1. 创建一个新表 - 我们称之为 tChar。
  2. 在其中放置一个文本字段 - 您要替换的字符 - 我们将char在此示例中调用它
  3. 将要删除的所有 char 或 char 组合放在此表中。
  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 而不是 service。在这里,您将输入您获得的每一个奇怪的排列。
  2. 使用 QualifierID 和 Plant ID 创建一个表。在这里,您会说哪个限定符用于哪个工厂。
  3. 创建一个查询,将两者和您的表连接起来,其中包含错误的植物名称。使用 instr 所以说出字段中的内容。
  4. 创建第二个查询来聚合第一个查询。计算 instr 字段并将其用作分数。得分最高的条目是植物。
  5. 您将不得不手动输入它找不到的那些,但很快就会几乎没有,因为表格中的条目越来越多。


你有几个不同的选择。Access中没有sql中的CASE,需要使用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,您还可以创建自己的函数并将它们放在查询中……但那是另一篇文章。:) HTH

于 2009-04-14T18:30:14.313 回答
1

在代码模块中创建一个公共函数。

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")
于 2009-04-14T19:54:22.490 回答
0

全部 - 我最终将 REPLACE() 函数嵌套在两个单独的查询中。由于我需要替换超过 35 个非字母数字字符,并且 Access 将查询的复杂性限制在 20 个嵌套函数左右,因此我只是将其拆分为两个进程。有点笨拙,但它确实有效。在这种情况下应该遵循 KISS 原则。谢谢你的帮助!

于 2009-04-16T21:44:40.597 回答
0

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

于 2009-04-14T18:28:42.913 回答
0

此查询获取前 3 个字符并将它们替换为空白

示例:BO-1234
输出:1234

BO: IIf(IsNumeric(Left([sMessageDetails],3)),[sMessageDetails],Replace([sMessageDetails],Left([sMessageDetails],3),""))
于 2019-05-20T14:39:40.323 回答
0

我知道这是一个非常古老的问题,但我在寻找解决此问题的方法时偶然发现了它,但最终使用了不同的方法。

我希望更新的字段称为“客户”。'CustName' 字段中有 20 多个重音字符,我希望删除它们的变音符号 - 所以(例如)ã > a。

对于这些字符中的每一个,我创建了一个新表“recodes”,其中包含 2 个字段“char”和“recode”。'char' 包含我希望删除的字符,而 'recode' 包含替换字符。

然后对于替换,我在更新语句中做了一个完整的外部连接

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

这与嵌套所有替换语句具有相同的效果,并且更易于管理。

于 2015-09-14T16:10:24.293 回答