我是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中做到了这一点并且收益率很高。任何人都可以推荐更好的解决方案吗?
答案 0 :(得分: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
答案 1 :(得分: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:
在回答有关问题的评论中的其他信息时,这里建议您如何以不同的方式处理这种情况。此apprach的优点是,一旦您在工厂名称中进行了映射排列,您将不需要在未来几年中对未来数据执行字符串替换,只需将新工厂名称和排列添加到地图中。
从创建另一个表开始,我们称之为plant_map
CREATE TABLE plant_map (id AUTOINCREMENT PRIMARY KEY, name TEXT, master_id LONG)
到plant_map
,添加工厂名称的所有排列,并在master_id字段中插入您希望用于引用特定工厂名称排列组的名称的id。根据您的评论,我将使用 Signode服务
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表时,您可以使用
获取 Signode服务的数据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 :(得分:2)
不要认为Access支持CASE语句。考虑使用iif:
iif ( condition, value_if_true, value_if_false )
对于这种情况,您可以使用REPLACE功能:
SELECT
REPLACE(REPLACE(REPLACE(yourfield, '#', ''), '-', ''), '/', '')
as FieldName
FROM
....
答案 3 :(得分:1)
好的,你的问题已经改变了,所以解决方案也是如此。这有两种方法。快速而肮脏的方式只能部分解决您的问题,因为它无法解决更多奇怪的排列,如缺失空格或拼写错误的单词。快速而肮脏的方式:
char
创建并运行以下查询。
请注意,它只会删除一个
项目一次,但你也可以
不同版本的相同
替换它也像' - '或
' - '
在本例中,我创建了一个名为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上使用我的用户名:
ughh
您有两种不同的选择。在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
答案 4 :(得分: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")
答案 5 :(得分:0)
SELECT
IIF
(
Instr(1,ShipToPlant , "#") > 0
OR Instr(1,ShipToPlant , "/") > 0
OR Instr(1,ShipToPlant , "-") > 0, ""
, ShipToPlant
)
FROM BTST
答案 6 :(得分:0)
全部 - 我在两个单独的查询中嵌套REPLACE()函数。由于我需要替换超过35个非字母数字字符,并且Access将查询的复杂性限制在大约20个嵌套函数的某个地方,我只是将它分成两个进程。有点笨重,但它奏效了。在这种情况下应该遵循KISS原则。谢谢你的帮助!
答案 7 :(得分:0)
I know this is a really old question, but I stumbled over it whilst looking for a solution to this problem, but ended up using a different approach.
The field that I wish to update is called 'Customers'. There are 20-odd accented characters in the 'CustName' field for which I wish to remove the diacritics - so (for example) ã > a.
For each of these characters I created a new table 'recodes' with 2 fields 'char' and 'recode'. 'char' contains the character I wish to remove, and 'recode' houses the replacement.
Then for the replace I did a full outer join inside the update statement
UPDATE Customers, Recodes SET Customers.CustName = Replace([CustName],[char],[recode]);
This has the same effect as nesting all of the replace statements, and is a lot easier to manage.
答案 8 :(得分:0)
此查询获取前3个字符并将其替换为空白
示例:BO-1234
输出:1234
BO: IIf(IsNumeric(Left([sMessageDetails],3)),[sMessageDetails],Replace([sMessageDetails],Left([sMessageDetails],3),""))