我有一个包含这样的数据的列。破折号表示同一发票的多份副本,这些副本必须按升序排序
790711
790109-1
790109-11
790109-2
我必须按此数字按递增顺序对其进行排序,但由于这是一个varchar字段,因此按字母顺序排序,如此
790109-1
790109-11
790109-2
790711
为了解决这个问题,我尝试用空替换 - (破折号),然后将其作为数字投射,然后对其进行排序
select cast(replace(invoiceid,'-','') as decimal) as invoiceSort...............order by invoiceSort asc
虽然这样更好并且像这样排序
invoiceSort
790711 (790711) <-----this is wrong now as it should come later than 790109
790109-1 (7901091)
790109-2 (7901092)
790109-11 (79010911)
有人建议我在 - (破折号)上拆分发票ID,并在2个分割部分上按顺序分开
像=====&GT; order by split1 asc,split2 asc (790109,1)
哪个会起作用我认为但是我将如何拆分列。
互联网上的各种拆分功能是那些返回表格的功能,而在这种情况下我需要一个标量功能。
还有其他方法可以使用吗?数据显示在网格视图中,并且网格视图默认情况下不支持在2列上进行排序(我可以实现它:))因此,如果有任何更简单的方法,我会非常好。
编辑:感谢所有答案。虽然每个答案都是正确的,但我选择的答案允许我将这些列合并到GridView排序中,并最小化sql查询的因子。
答案 0 :(得分:4)
试试这个 -
<强>查询:强>
DECLARE @Invoice TABLE (InvoiceNumber VARCHAR(10))
INSERT @Invoice
VALUES
('790711')
, ('790709-1')
, ('790709-21')
, ('790709-11')
, ('790709-211')
, ('790709-2')
;WITH cte AS
(
SELECT
InvoiceNumber
, lenght = LEN(InvoiceNumber)
, delimeter = CHARINDEX('-', InvoiceNumber)
FROM @Invoice
)
SELECT InvoiceNumber
FROM cte
CROSS JOIN (
SELECT repl = MAX(lenght - delimeter)
FROM cte
WHERE delimeter != 0
) mx
ORDER BY
SUBSTRING(InvoiceNumber, 1, ISNULL(NULLIF(delimeter - 1, -1), lenght))
, RIGHT(REPLICATE('0', repl) + SUBSTRING(InvoiceNumber, delimeter + 1, lenght), repl)
<强>输出:强>
InvoiceNumber
-------------
790709-1
790709-2
790709-11
790709-21
790709-211
790711
答案 1 :(得分:3)
明智地使用REVERSE
,CHARINDEX
和SUBSTRING
,可以获得我们想要的效果。我在下面的代码中使用了希望解释的列名来说明发生了什么。
设置样本数据:
DECLARE @Invoice TABLE (
InvoiceNumber nvarchar(10)
);
INSERT @Invoice VALUES
('790711')
,('790709-1')
,('790709-11')
,('790709-21')
,('790709-212')
,('790709-2')
SELECT * FROM @Invoice
示例数据:
InvoiceNumber
-------------
790711
790709-1
790709-11
790709-21
790709-212
790709-2
这是代码。我有一种唠叨的感觉,最终的表达方式可以简化。
SELECT
InvoiceNumber
,REVERSE(InvoiceNumber)
AS Reversed
,CHARINDEX('-',REVERSE(InvoiceNumber))
AS HyphenIndexWithinReversed
,SUBSTRING(REVERSE(InvoiceNumber),1+CHARINDEX('-',REVERSE(InvoiceNumber)),LEN(InvoiceNumber))
AS ReversedWithoutAffix
,SUBSTRING(InvoiceNumber,1+LEN(SUBSTRING(REVERSE(InvoiceNumber),1+CHARINDEX('-',REVERSE(InvoiceNumber)),LEN(InvoiceNumber))),LEN(InvoiceNumber))
AS AffixIncludingHyphen
,SUBSTRING(InvoiceNumber,2+LEN(SUBSTRING(REVERSE(InvoiceNumber),1+CHARINDEX('-',REVERSE(InvoiceNumber)),LEN(InvoiceNumber))),LEN(InvoiceNumber))
AS AffixExcludingHyphen
,CAST(
SUBSTRING(InvoiceNumber,2+LEN(SUBSTRING(REVERSE(InvoiceNumber),1+CHARINDEX('-',REVERSE(InvoiceNumber)),LEN(InvoiceNumber))),LEN(InvoiceNumber))
AS int)
AS AffixAsInt
,REVERSE(SUBSTRING(REVERSE(InvoiceNumber),1+CHARINDEX('-',REVERSE(InvoiceNumber)),LEN(InvoiceNumber)))
AS WithoutAffix
FROM @Invoice
ORDER BY
-- WithoutAffix
REVERSE(SUBSTRING(REVERSE(InvoiceNumber),1+CHARINDEX('-',REVERSE(InvoiceNumber)),LEN(InvoiceNumber)))
-- AffixAsInt
,CAST(
SUBSTRING(InvoiceNumber,2+LEN(SUBSTRING(REVERSE(InvoiceNumber),1+CHARINDEX('-',REVERSE(InvoiceNumber)),LEN(InvoiceNumber))),LEN(InvoiceNumber))
AS int)
输出:
InvoiceNumber Reversed HyphenIndexWithinReversed ReversedWithoutAffix AffixIncludingHyphen AffixExcludingHyphen AffixAsInt WithoutAffix
------------- ---------- ------------------------- -------------------- -------------------- -------------------- ----------- ------------
790709-1 1-907097 2 907097 -1 1 1 790709
790709-2 2-907097 2 907097 -2 2 2 790709
790709-11 11-907097 3 907097 -11 11 11 790709
790709-21 12-907097 3 907097 -21 21 21 790709
790709-212 212-907097 4 907097 -212 212 212 790709
790711 117097 0 117097 0 790711
请注意,您实际需要的只是ORDER BY
子句,其余的只是为了显示我的工作,这是这样的:
int
。幸运的是,我们从SQL Server中获得了一个突破,因为这个转换为空字符串提供了零。ORDER BY
(没有任何词缀的数字),然后是(词缀的数值)。这是我们寻求的最终订单。如果SQL Server允许我们说SUBSTRING(value, start)
从该点开始获取字符串,那么代码会更简洁,但事实并非如此,所以我们不得不说SUBSTRING(value, start, LEN(value))
。< / p>
答案 2 :(得分:3)
试试这个
SELECT invoiceid FROM Invoice
ORDER BY
CASE WHEN PatIndex('%[-]%',invoiceid) > 0
THEN LEFT(invoiceid,PatIndex('%[-]%',invoiceid)-1)
ELSE invoiceid END * 1
,CASE WHEN PatIndex('%[-]%',REVERSE(invoiceid)) > 0
THEN RIGHT(invoiceid,PatIndex('%[-]%',REVERSE(invoiceid))-1)
ELSE NULL END * 1
<强> SQLFiddle Demo 强>
以上查询使用两个案例陈述
详细了解请查看以下SQLfiddle
<强> SQLFiddle Detailed Demo 强>
或使用'CHARINDEX'
SELECT invoiceid FROM Invoice
ORDER BY
CASE WHEN CHARINDEX('-', invoiceid) > 0
THEN LEFT(invoiceid, CHARINDEX('-', invoiceid)-1)
ELSE invoiceid END * 1
,CASE WHEN CHARINDEX('-', REVERSE(invoiceid)) > 0
THEN RIGHT(invoiceid, CHARINDEX('-', REVERSE(invoiceid))-1)
ELSE NULL END * 1
答案 3 :(得分:2)
每个部分分别订购是最简单可靠的方法,为什么要寻找其他方法?看看这个简单的查询。
select *
from Invoice
order by Convert(int, SUBSTRING(invoiceid, 0, CHARINDEX('-',invoiceid+'-'))) asc,
Convert(int, SUBSTRING(invoiceid, CHARINDEX('-',invoiceid)+1, LEN(invoiceid)-CHARINDEX('-',invoiceid))) asc
答案 4 :(得分:2)
这里有很多好的答案,但我认为这个可能是最紧凑的有效订单条款:
SELECT *
FROM Invoice
ORDER BY LEFT(InvoiceId,CHARINDEX('-',InvoiceId+'-'))
,CAST(RIGHT(InvoiceId,CHARINDEX('-',REVERSE(InvoiceId)+'-'))AS INT)DESC
演示: - SQL Fiddle
注意,我在测试中添加了'790709'版本,因为这里列出的一些方法并没有将后缀版本视为小于后缀版本。
如果您的invoiceID长度不同,那么在' - '之前,您需要:
SELECT *
FROM Invoice
ORDER BY CAST(LEFT(list,CHARINDEX('-',list+'-')-1)AS INT)
,CAST(RIGHT(InvoiceId,CHARINDEX('-',REVERSE(InvoiceId)+'-'))AS INT)DESC
在破折号之前使用不同长度的演示:SQL Fiddle
答案 5 :(得分:1)
我的版本:
declare @Len int
select @Len = (select max (len (invoiceid) - charindex ( '-', invoiceid))-1 from MyTable)
select
invoiceid ,
cast (SUBSTRING (invoiceid ,1,charindex ( '-', invoiceid )-1) as int) * POWER (10,@Len) +
cast (right(invoiceid, len (invoiceid) - charindex ( '-', invoiceid) ) as int )
from MyTable
您可以将其实现为表格的新列:
ALTER TABLE MyTable ADD COLUMN invoice_numeric_id int null
GO
declare @Len int
select @Len = (select max (len (invoiceid) - charindex ( '-', invoiceid))-1 from MyTable)
UPDATE TABLE MyTable
SET invoice_numeric_id = cast (SUBSTRING (invoiceid ,1,charindex ( '-', invoiceid )-1) as int) * POWER (10,@Len) +
cast (right(invoiceid, len (invoiceid) - charindex ( '-', invoiceid) ) as int )
答案 6 :(得分:1)
一种方法是将InvoiceId
拆分为其部分,然后对部件进行排序。这里我使用派生表,但也可以使用CTE或临时表来完成。
select InvoiceId, InvoiceId1, InvoiceId2
from
(
select
InvoiceId,
substring(InvoiceId, 0, charindex('-', InvoiceId, 0)) as InvoiceId1,
substring(InvoiceId, charindex('-', InvoiceId, 0)+1, len(InvoiceId)) as InvoiceId2
FROM Invoice
) tmp
order by
cast((case when len(InvoiceId1) > 0 then InvoiceId1 else InvoiceId2 end) as int),
cast((case when len(InvoiceId1) > 0 then InvoiceId2 else '0' end) as int)
在上文中,InvoiceId1
和InvoiceId2
是InvoiceId
的组成部分。 外部 select
包含这些部分,但仅用于演示目的 - 您无需在选择中执行此操作。
派生表(内部select
)抓取InvoiceId
以及组件部分。它的工作方式是:
InvoiceId
中有短划线时,InvoiceId1
将包含数字的第一部分,InvoiceId2
将包含第二部分。InvoiceId1
将为空,InvoiceId2
将包含整个数字。上面的第二个案例(没有破折号)不是最佳的,因为理想情况下InvoiceId1
将包含数字,InvoiceId2
将为空。为了使内部选择最佳地工作会降低选择的可读性。我选择了非最佳,更易读的方法,因为它足以允许排序。
这就是ORDER BY
子句测试长度的原因 - 它需要处理上面两种情况。
答案 7 :(得分:1)
将排序分为两部分:
MS SQL Server 2008架构设置:
CREATE TABLE TestData
(
data varchar(20)
)
INSERT TestData
SELECT '790711' as data
UNION
SELECT '790109-1'
UNION
SELECT '790109-11'
UNION
SELECT '790109-2'
查询1 :
SELECT *
FROM TestData
ORDER BY
FLOOR(CAST(REPLACE(data, '-', '.') AS FLOAT)),
CASE WHEN CHARINDEX('-', data) > 0
THEN CAST(RIGHT(data, len(data) - CHARINDEX('-', data)) AS INT)
ELSE 0
END
<强> Results 强>:
| DATA |
-------------
| 790109-1 |
| 790109-2 |
| 790109-11 |
| 790711 |
答案 8 :(得分:0)
尝试:
select invoiceid ... order by Convert(decimal(18, 2), REPLACE(invoiceid, '-', '.'))