C# 如何仅获取最新的发票号码

C# 如何仅获取最新的发票号码,c#,sql-server,linq,C#,Sql Server,Linq,我有存储为nvarchar(25)的发票号码 它们的格式是“#####AA” 其中#####是发票号,AA是版本号(部分订单发货) 我无法更改格式 我创建了两个标量函数: CREATE FUNCTION [dbo].[fnNumbersFromStr](@str varchar(8000)) RETURNS int AS BEGIN WHILE PATINDEX('%[^0-9]%',@str)> 0 SET @str = REPLACE(@str, SUBSTRING(@str,

我有存储为nvarchar(25)的发票号码

它们的格式是“#####AA” 其中#####是发票号,AA是版本号(部分订单发货) 我无法更改格式

我创建了两个标量函数:

CREATE FUNCTION [dbo].[fnNumbersFromStr](@str varchar(8000))
RETURNS int
AS
BEGIN
  WHILE PATINDEX('%[^0-9]%',@str)> 0
  SET @str = REPLACE(@str, SUBSTRING(@str, PATINDEX('%[^0-9]%', @str), 1), '')
  RETURN CAST(@str AS INT)
END
那是我的兄弟:

CREATE FUNCTION [dbo].[fnStringFromNum](@str varchar(25))
RETURNS varchar(25)
AS
BEGIN
  WHILE PATINDEX('%[^a-z]%',@str)> 0
  SET @str = REPLACE(@str, SUBSTRING(@str, PATINDEX('%[^a-z]%', @str), 1), '')
  RETURN @str
END
我被这个脚本耽搁了:

SELECT
strInvoiceNo,
    dbo.fnNumbersFromStr(strInvoiceNo) AS [InvoiceNumber],
    dbo.fnStringFromNum(strInvoiceNo) AS [InvoiceString]
FROM @TempTable
当运行返回时:

strInvoiceNo InvoiceNumber InvoiceString
1000A 1000 A
1000B 1000 B
1000C 1000 C
1001A 1001 A
1001B 1001 B
1002AA 1002 AA
1002AB 1002 AB
1003A 1003 A
1004A 1004 A
strInvoiceNo发票编号发票字符串
1000A 1000A
1000B 1000B
1000摄氏度1000摄氏度
1001A 1001A
1001B 1001B
1002AA 1002AA
1002AB 1002AB
1003A 1003 A
1004A 1004 A
我就是想不出下一步该怎么办。我被卡住了

我希望选择仅返回最新的发票版本:

1000C
1001B
1002AB
1003A
1004A

Sql、Lamda或Linq对我来说都很好

提前感谢,

试试这个:

SELECT
  InvoiceNumber + MAX(InvoiceString) As strInvoiceNo    
FROM
(
   SELECT
       dbo.fnNumbersFromStr(strInvoiceNo) AS [InvoiceNumber],
       dbo.fnStringFromNum(strInvoiceNo) AS [InvoiceString]
   FROM @TempTable
) As tbl
GROUP BY InvoiceNumber

不一定是最有效的,但这会起作用:

select strInvoiceNo
from @TempTable T
where InvoiceString = (select max(invoicestring) from temp1 where invoicenumber = T.invoicenumber)
order by 1

编辑:对不起……忽略。这将从您的完整结果表中删除,但可能不是您实际需要的。抱歉。

我认为您不需要任何自定义项,一个简单的窗口函数查询应该会返回您想要的内容

WITH x AS
(
 Select *
       ,ROW_NUMBER() OVER (PARTITION BY InvoiceNumber ORDER BY strInvoiceNo DESC) rn 
 FROM TableName
)
SELECT strInvoiceNo, InvoiceNumber, InvoiceString 
FROM X 
WHERE rn = 1

以下是LINQ中的字符串(假设fnStringFromNum返回一个在左侧填充空格的字符串):

SQL(使用当前fnStringFromNum):


如果您有很多行,您可能需要考虑使用内联表值函数而不是标量函数,因为这样可以将两个值都返回一个操作,假设它总是数字+代码——但是,不管怎么说,编写代码要稍微困难一些:)您可以通过拆分为两列
invoiceNum
invoicePostfix
之类的内容来简化您的工作。它还允许您进行更好的查询,从而执行得更快。例如按num desc排序,然后按postfix desc排序,先取。这在@Magnus中非常有效!但是,我确实需要更改我的第一个函数以返回varchar,而不是将其转换为int。这只是提醒您,这实际上不会起作用,但得到的答案基本上是正确的。一旦发票版本达到Z,InvoiceString部分将失败,因为下一个版本AA在获得最大值时不大于Z。我非常喜欢您的实现@M.Ali,但是拥有一个函数对我来说不是什么大问题。我需要排序的记录数很可能一次少于200条。我只查看未结发票,而不是所有过去和现在的发票。感谢您的输入@Robert。我看到的唯一问题是AccountNumber字段(我的问题中的代表)没有固定,因为只有四位数长。对不起,我没有在原来的帖子中提到这一点。不过,此答案简短而甜蜜,可能会持续一段时间。请使用
fnNumbersFromStr
函数更新答案,但您需要对其进行映射,以便可以像上面那样使用它。我想问的一个问题是。。
AB
B
之后的一个版本,还是
a
的一个子版本,然后介于
a
B
之间?您可能只需要在发票表上创建两个计算列,以调用AccountNumber上的自定义项。将来可能会为你简化事情。类似:
ALTER TABLE dbo.Invoices将InvoiceNumber添加为dbo.fnNumbersFromStr(AccountNumber);更改表dbo.Invoices将InvoiceRevision添加为dbo.fnStringFromNum(AccountNumber)
版本“Z”之后的下一个版本将是“AA”,然后是“AB”,然后是“AC”,依此类推。。。顺便说一句,我认为从Linq调用UDF(EntityFramework6首先使用模型)不起作用?对我来说,实际的表是只读的,数据库是第三方的。然后你需要在排序之前右键填充字符串,否则
AA
将介于
A
B
之间。Linq的UDF在EF 6中运行良好。不过,我们先使用数据库,所以我不确定这是否是一个问题。您可以这样填充:
RIGHT(空格(20)+somefield,20)
将20更改为您认为最多的数字。
SELECT strInvoiceNo, InvoiceNumber, InvoiceString 
FROM 
(
 Select *
       ,ROW_NUMBER() OVER (PARTITION BY InvoiceNumber ORDER BY strInvoiceNo DESC) rn 
 FROM TableName
)x
WHERE rn = 1
dbContext.YOURTABLE
  .GroupBy(x=>UDFFunctions.fnNumbersFromStr(x.AccountNumber))
  .Select(x=>x.OrderByDescending(y=>UDFFunctions.fnStringFromNum(y.AccountNumber).FirstOrDefault())
SELECT
  InvoiceNumber + LTRIM(MAX(RIGHT(SPACE(20)+InvoiceString,20))) As strInvoiceNo    
FROM
(
   SELECT
       dbo.fnNumbersFromStr(strInvoiceNo) AS [InvoiceNumber],
       dbo.fnStringFromNum(strInvoiceNo) AS [InvoiceString]
   FROM @TempTable
) As tbl
GROUP BY InvoiceNumber