この問題を解決する方法と、醜いが簡単に理解できるコードを提供する方法を、一般的な考え方を最初に示します。次に、問題の内容と解決方法について説明します。
STEP 1:最初のステップのためのグループ化基準
の導出、私はあなたがあなたのテーブルに追加の列を作成する権利(権限)を持っていると仮定します。それをinvoice_text
と名付けましょう。今、一般的な考え方は、 "テキストパターン"だけが残るように請求書番号からすべての数字を削除することです。次に、テキストパターンでグループ化することができます。
あなたが次のことを行うことができ、あなたはすでに上記の列を作成したと仮定すると:あなたはinvoice_text
の桁なしで純粋なテキストパターンを持つことになりますし、グループ化のためにそれを使用することができることを行わした後
UPDATE Invoices SET invoice_text = REPLACE(invoice_number, '0', '');
UPDATE Invoices SET invoice_text = REPLACE(invoice_text, '1', '');
UPDATE Invoices SET invoice_text = REPLACE(invoice_text, '2', '');
...
UPDATE Invoices SET invoice_text = REPLACE(invoice_text, '9', '');
:
SELECT COUNT(invoice_number) AS total_invoices FROM Invoices
GROUP BY invoice_text
これは素晴らしいですが、まだあなたが望むものではありません。各グループの最初と最後の請求書番号は表示されません。
STEP 2:あなたのテーブル内の1つの以上の列を作成し、このステップでは、各グループ
ための最初と最後の請求書を導出します。それをinvoice_digits
と名付けましょう。名前が意味するように、それは "パターンテキスト"なしで純粋な請求書番号だけを取ることを意味します。
あなたはその列を持っていると仮定すると、次の行うことができます:
SELECT
MIN(invoice_digits) AS from_invoice_no,
MAX(invoice_digits) AS to_invoice_no,
COUNT(invoice_number) AS total_invoices
FROM Invoices
GROUP BY invoice_text
:今
UPDATE Invoices SET invoice_digits = REPLACE(invoice_number, 'A', '');
UPDATE Invoices SET invoice_digits = REPLACE(invoice_digits, 'B', '');
UPDATE Invoices SET invoice_digits = REPLACE(invoice_digits, 'C', '');
...
UPDATE Invoices SET invoice_digits = REPLACE(invoice_digits, 'Z', '');
を、あなたは(「パターンテキスト」なし)最小と最大の請求書番号を取得するには、その列を使用することができます
の問題とあなたによると、彼らに
1)を解決する方法あなたは最小と最大のフルインボイス番号のテキストを取得したいと考えています。上記の解決策では、テキスト部分のない最小および最大請求書番号テキストのみが表示されます。つまり、数字のみです。
JOIN
をこれを修正することができますが、私はあなたがこれを主張しないと想像することができます:-)、そして一般的なアイデアをより明確にしないので、私はこれを残していますあなたへ。興味があれば、私たちに知らせてください。
2)実際の請求書数)である、すなわち何(何桁を決定することは困難かもしれません。たとえば、INV001
、INV002
のような請求書番号がある場合、これは問題ありませんが、INV001/001
,INV001/002
,INV002/003
などがある場合はどうなりますか?この例では、私のコードは001001
、001002
、002003
を実際の請求書番号とし、それを使って最小値と最大値が何であるかを決定します。
この場合、これはあなたがしたいことではないかもしれません。これを回避する唯一の方法は、数字を考慮する必要があるものとそうでないものを徹底的に考え、それに応じてコードを適合させることです。
3)現在のところ、私のコードでは文字列の比較を使用して、最小および最大の請求書番号を取得しています。これは数値を数値として比較する以外の結果をもたらす可能性があります。それが何を意味するのか疑問に思っている場合:'19'
と'9'
を文字列として比較し、19
を9
と数字を比較してください。
これが問題の場合は、を使用してテキストを数値に変換してから、MAX
またはMIN
に入力してください。しかし、これには独自の注意点がありますのでご注意ください。
数値が非常に長いインボイス番号がMySQLの数値データ型に適合しない場合、この方法は失敗します。 /
のような文字を(2で説明した問題のため)数字にすると、MySQLは数字に変換できないため、これも失敗します。
数値に変換する代わりに、の値を先行するゼロで埋め込むこともできます。たとえば、MySQLのLPAD
関数を使用します。これは上記の問題を回避し、/
のような非数字が含まれていても数値を期待どおりにソートしますが、数字の文字列の最大長を事前に知る必要があります。
4)コードは醜いです!数字の文字列を取得するためにUPDATE
文を実行して、A
からZ
までのすべての文字を1つずつ削除する必要がありますか?
実際、さらに悪化しています。私はちょうどをと仮定しましたが、あなたの請求書には「テキスト文字」A
〜Z
しかありません。しかし、Unicodeには、ロシア語や中国語の文字、特殊文字、つまり何千もの異なる文字が定義されている可能性があります。
残念ながら、AFAIK、MySQLはまだREGEX-REPLACE機能を提供していません。適切なUDF(ユーザー定義関数)でMySQLを拡張しない限り、この問題を解決する機会はありません。問題を認識してMySQLにそのような機能を追加したクールな人がいます。ライブラリを推薦するので、SOには、単に "Googleの正規表現の置き換え"のGoogleに落胆しているようだ。
このようにMySQLを拡張すると、UPDATE
の醜い束を置き換えることができます。これは、桁数字/テキストを1つずつ削除します(REGEXを使用して、すべての桁またはすべての非桁すぐに)。
UPDATE ... SET ... = REPLACE(REPLACE(REPLACE(...)))
を実行して1つのステートメントですべての更新を適用することで、多くのUPDATE
ステートメントを避けることができます。しかし、これはさらに醜いとエラーが発生しやすいので、あなたが問題について深刻な場合、あなたは本当にREGEX - REPLACEによってMySQLを拡張する必要があります。
5)解決策は、テーブルに新しい列を作成する権限がある場合にのみ機能します。
これはそのままのソリューションに当てはまります。しかし、私はそれが一般的なアイデアをはっきりと理解できるようにするために、その道を行くことを選択しました。元のテーブルに列を追加する代わりに、純粋なテキスト/数字を格納する新しいテーブルを作成することもできます(このテーブルは一時的なものかもしれません)。
さらに、MySQLでは計算値によるグループ化がサポートされているため、追加の列/テーブルはまったく必要ありません。最善の方法は何かを自分で決めるべきです。
請求書番号には常に2つの部分があります.1つの部分は連続した数字で、残りの部分は連続した非数字です。また、請求書番号は「001INV003FOO1234BAR」のようになりますか? – Binarus
はい、「PRCMMU1718/00057」、「PRCMMU1718/00058」、「AQW1025」、「AQW1028」、「AQW1030」、「1258POC」、「1259POC」... – pmenezes
はい、許可されていますか(つまり、 )を使用してそのテーブルに2つの列を追加するか、新しいテーブルを作成しますか? – Binarus