首先,我希望这完全是用MySQL查询完成的。
我有一系列发票号码
invoice_number
INV001
INV002
INV003
INV004
INV005
001
002
003
006
007
009
010
INVOICE333
INVOICE334
INVOICE335
INVOICE337
INVOICE338
INVOICE339
001INV
002INV
005INV
009INV
我想输出类似的东西
from_invoice_no to_invoice_no total_invoices
INV001 INV005 5
001 010 7
INVOICE333 INVOICE339 6
001INV 009INV 4
无法修复发票编号图案。他们将来可以改变
请帮助我实现这一目标。
提前致谢。
答案 0 :(得分:0)
我将首先展示如何解决此问题并提供一些丑陋但易于理解的代码。然后,我将解释问题是什么以及如何纠正它们。
第1步:推导分组标准
对于第一步,我假设您有权(特权)在表中创建其他列。我们将其命名为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', '');
完成此操作后,您将拥有invoice_text
中没有数字的纯文本模式,并可以将其用于分组:
SELECT COUNT(invoice_number) AS total_invoices FROM Invoices
GROUP BY invoice_text
这很好,但它还不是你想要的。它不显示每个组的第一个和最后一个发票号。
第2步:派生每个小组的第一张和最后一张发票
对于此步骤,请在表格中再创建一列。我们将其命名为invoice_digits
。顾名思义,它只用于没有"模式文本"的纯发票号。
假设您有该列,则可以执行以下操作:
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', '');
现在,您可以使用该列获取最小和最大发票号(不包含#34;模式文本"):
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
问题以及如何解决这些问题
1)根据您的问题,您希望获得最小和最大完整发票号码文本。上述解决方案仅显示没有文本部分的最小和最大发票编号文本,即仅显示数字。
我们可以通过进一步JOIN
来解决这个问题,但是因为我很好地想象你不会坚持这个:-),因为它不会成为一般的想法更清楚,我把这个留给你。如果您有兴趣,请告诉我们。
2)可能很难确定一个数字(即实际发票数字)是什么。例如,如果您有INV001
,INV002
等发票号码,这将没有问题,但如果您有INV001/001
,INV001/002
,INV002/003
和等等?在此示例中,我的代码会将001001
,001002
,002003
作为实际发票编号,并使用它来确定最小和最大数字。
在这种情况下,这可能不是您想要做的。解决这个问题的唯一方法就是你要彻底考虑你应该考虑什么,不应该考虑什么,以及相应地调整我的代码。
3)我的代码目前使用字符串比较来获取最小和最大发票号。除了将值作为数字进行比较之外,这可能产生其他结果如果您想知道这意味着什么:将'19'
与'9'
比较为字符串,并将19
与9
作为数字进行比较。
如果这是一个问题,请使用MySQL CAST
将文本转换为数字,然后再将其转移到MAX
或MIN
。但请注意,这有其自己的警告:
如果您的发票号很长且数字太多,以至于它们不适合MySQL的数字数据类型,则此方法将失败。如果您将/
之类的字符定义为数字(由于2中描述的问题),它也将失败,因为MySQL无法将其转换为数字。
您也可以使用MySQL invoice_digits
函数填充LPAD
中带有前导零的值,而不是转换为数字。这样可以避免上述问题并按预期对数字进行排序,即使它们包含非数字/
,但您必须事先知道数字字符串的最大长度。
4)代码很难看!您是否真的需要通过执行A
语句逐个删除Z
到UPDATE
中所有可能的字符来获取数字字符串?
实际上,情况更糟。我只是假设你只有#34;文本字符"发票中A
到Z
。但是Unicode可以定义任何字符:俄语或中文字符,特殊字符,换句话说:数千个不同的字符。
不幸的是,AFAIK,MySQL仍然没有提供REGEX-REPLACE功能。除非您使用适当的UDF(用户定义的函数)扩展MySQL,否则我没有看到任何机会解决此问题。有一些很酷的人已经认识到这个问题,并已将这些功能添加到MySQL。由于推荐图书馆似乎不鼓励SO,只需google for" mysql regex replace"。
当以这种方式扩展MySQL时,您可以替换丑陋的UPDATE
语句,这些语句将发票号中的数字/文本删除一个(使用REGEX,您可以替换所有数字或全部一次非数字。)
为了完整起见,您可以通过执行UPDATE
来避免许多UPDATE ... SET ... = REPLACE(REPLACE(REPLACE(...)))
语句,从而将所有更新应用于一个语句。但这更加丑陋且容易出错,所以如果你认真对待你的问题,那么你真的必须通过REGEX-REPLACE扩展MySQL。
5)只有您有权在表格中创建新列时,该解决方案才有效。
对于解决方案,这是正确的。但我选择这样做只是因为它使一般的想法清晰易懂。您也可以创建一个新表来存储纯文本/数字(此表可能是临时表),而不是将列添加到原始表中。
此外,由于MySQL支持按计算值进行分组,因此您根本不需要额外的列/表。你应该自己决定最好的方法。