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'."

"*"ワイルドカードであるため、キーボードのすべての文字に対してこの操作を実行したいと考えています。

あなたが提供できるどんな助けも大歓迎です!

編集:コメントから追加された背景情報

私は、2008 暦年の 14 のサプライヤーそれぞれから明細項目の請求書レベルのデータを収集しました。サプライヤーから提供された植物名を正規化しようとしています。

各サプライヤーは、プラントを異なる名前で呼ぶことができます。

マスター リストにあるSignode Serviceは、サプライヤーによって呼び出される可能性があります

Signode Service 
Signode - Service.
SignodeSvc
SignodeService

最初の 10 文字を参照する一連のリンクを作成することにより、マスター リストを使用して植物を識別できるように、英数字以外の文字を削除しようとしています。一致しない場合は、8 文字、6、4...

私の基本的なハングアップは、テーブルから英数字を削除する方法がわからないことです。この操作は複数の列で実行しますが、他の列を編集するために個別のクエリを作成する予定でした。

おそらく、すべての英数字を削除する一括更新クエリを実行する必要があります。書き方がいまいちわかりません。これが、すべてのスペースを取り除くために私が始めたものです。うまくいきましたが、置換をネストしようとすると失敗しました

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

EDIT 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 フィールドに挿入します。あなたのコメントから、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 テーブルにクエリを実行すると、以下を使用して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は変更されないままにすることができます。

基本的に、これは植物名を名前に結合しBTSTplant_mapを使用してmaster_id自己結合するidためplant_map、「共通の」名前を 1 つだけ渡す必要があります。両方のフィールドが結合で使用されるため、各列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

OK、質問が変更されたので、解決策も変更されます。これを行うには2つの方法があります。スペースの欠落や単語のスペルミスなどのより奇妙な順列を説明できないため、迅速で汚い方法では問題を部分的にしか解決できません。手っ取り早い方法:

  1. 新しいテーブルを作成します - tChar としましょう。
  2. その中にテキストフィールドを入れます - 置き換えたい文字 -charこの例ではそれを呼び出します
  3. 削除したいすべての文字または文字の組み合わせをこの表に入れます。
  4. 以下のクエリを作成して実行します。一度に 1 つのアイテムしか削除されないことに注意してください。ただし、'-' や '-' のように、同じ置換の異なるバージョンをその中に入れることもできます。この例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. Qualifiers の表を作成します - service ではなく svc のように人々が入力する間違い。ここでは、取得したすべての奇妙な順列を入力します。
  2. QualifierID と Plant ID を使用してテーブルを作成します。ここでは、どのクオリファイアーがどのプラントに送られるかを示します。
  3. 間違った植物名を含むテーブルと 2 つを結合するクエリを作成します。instr を使用して、フィールドにあるものを言います。
  4. 最初のクエリを集計する 2 番目のクエリを作成します。instr フィールドを数えてスコアとして使用します。最高得点のエントリは植物です。
  5. 見つからないものは手動で入力する必要がありますが、テーブル内のエントリがますます増えているため、すぐにほとんどなくなります。

うーん


いくつかの異なる選択肢があります。Access では、SQL に CASE はありません。IIF を使用する必要があります。これは、より堅牢な db エンジンのソリューションほど洗練されておらず、このインスタンスではネストする必要がありますが、作業は完了します。

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 に答える
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

これは非常に古い質問であることは知っていますが、この問題の解決策を探しているときにつまずきましたが、別のアプローチを使用することになりました。

更新したいフィールドは「Customers」です。「CustName」フィールドには、分音符号を削除したい 20 個の奇数のアクセント付き文字があります。つまり、(たとえば) ã > a.

これらの文字ごとに、「char」と「recode」の 2 つのフィールドを持つ新しいテーブル「recodes」を作成しました。「char」には削除したい文字が含まれ、「recode」には置換が含まれます。

次に、置換のために、更新ステートメント内で完全な外部結合を行いました

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

これは、すべての replace ステートメントをネストするのと同じ効果があり、管理がはるかに簡単です。

于 2015-09-14T16:10:24.293 に答える
0

すべて - 2 つの別々のクエリで REPLACE() 関数をネストすることになりました。置換する必要がある英数字以外の文字は 35 文字以上あり、Access ではクエリの複雑さがネストされた関数の約 20 個に制限されているため、クエリを 2 つのプロセスに分割しただけです。やや不格好ですが、うまくいきました。この場合、KISS の原則に従うべきでした。ご協力いただきありがとうございます!

于 2009-04-16T21:44:40.597 に答える