从一个记录拆分数据是特定的列T-SQL

时间:2017-10-04 19:57:12

标签: sql-server function split substring max

我正在处理从Oracle导入SQL Server 2012的旧旧数据库。我有一个名为INSOrders的下表,其中包含OrderIDvarchar(8)的列。

插入数据的一个例子是:

A04-05  |  B81-02  |  C02-01
A01-01  |  B95-01  |  C99-05
A02-02  |  B06-07  |  C03-02
A98-06  |  B10-01  |  C17-01
A78-07  |  B02-03  |  C15-03
A79-01  |  B02-01  |  C78-06

第一个字母= Ordertype,接下来的2个数字=年份 - 最后2个数字=该年内的OrderNum。

所以我将所有数据分成3列:(未存储,只是呈现)

select 
    orderid,
    substring(orderid, 0, patindex('%[0-9]%', orderid)) as ordtype,
    right(max(datepart(yyyy, '01/01/' + substring(orderid, patindex('%[0-9]-%', orderid) - 1, 2))),2) as year,
    max(substring(orderid, patindex('%-[0-9]%', orderid) + 1, 2)) as ordnum
from 
    ins.insorders
where 
    orderid is not null
group by 
    substring(orderid, 0, patindex('%[0-9]%', orderid)), orderid
order by 
    ordtype

看起来像这样:

OrderID  |  OrderType  |  OrderYear  | OrderNum
---------+-------------+-------------+----------
A04-05   |  A          |  04         |  05
A01-01   |  A          |  01         |  01
B10-03   |  B          |  10         |  03
B95-01   |  B          |  95         |  01
etc....

但现在我只想为所有OrderType选择最大值:仅显示字母A的最大值,显示字母B的最大值等等。我的意思是Max,我的意思是来自字母AI需要显示最新年份和最新订单号。所以,如果我有A04-01和A04-02,请显示A04-02。

我需要修改我的查询,我可以看到以下内容:

OrderID  |  OrderType  |  OrderYear  | OrderNum
---------+-------------+-------------+----------
A04-05   |  A          |  04         |  05
B10-03   |  B          |  10         |  03
C17-01   |  C          |  17         |  01

谢谢,我将非常感谢您的帮助。

3 个答案:

答案 0 :(得分:1)

您可以尝试以下方法。将原始查询用作cte,并根据订单年份和订单号为每组订单类型分配行号。然后获取所有第1行的行,这应该是每种订单类型的最大值。

这一点DATEPART(yyyy,('01/01/' + OrderYear))将确保我们得到正确的年份,以便95年是1995年,10年是2010年等。

   ;WITH cte 
    AS (
    select orderid,
    substring(orderid, 0, patindex('%[0-9]%', orderid)) as ordtype,
    right(max(datepart(yyyy,'01/01/' + substring(orderid, patindex('%[0-9]-%', orderid) - 1, 2))),2) as year,
    max(substring(orderid, patindex('%-[0-9]%', orderid) + 1, 2)) as ordnum
    from ins.insorders
    where orderid is not null
    group by substring(orderid, 0, patindex('%[0-9]%', orderid)), orderid
    )

SELECT *
FROM
  (SELECT 
        *
      , ROW_NUMBER() OVER (PARTITION BY OrderType ORDER BY DATEPART(yyyy,('01/01/' + OrderYear)) DESC, OrderNum DESC) AS RowNum
    FROM cte) t
WHERE t.RowNum = 1

答案 1 :(得分:0)

数据代表性很差,我只有一种“干酪”的方式,我们需要做出很多假设:

with cte_example
as
( your query )
select OrderID
       ,OrderType
       ,OrderYear
       ,OrderNum
from
(select *, row_number() over(partition by OrderType order by OrderYear DESC) rn      
from cte_example
where OrderYear <= right(year(getdate()),2)) t1
where t1.rn = 1

由于您已经有一个查询提取信息,我不打算改变它。我们将您的查询包装在CTE中,从中查询并应用row_number函数来确定哪个OrderType具有最新OrderYear,以及OrderNum和{{1} }}

现在棘手的部分是这些年代表现不佳(假设我对你原来的帖子的评论是真的),然后对OrderID OrderType使用任何类型的聚合将返回B因为它在数量上是最大的。

我们假设订单日期不会大于当前年份,并且使用此声明{90}更多的是90年代。95。换句话说,得到今年和它的两个正确的字符。首先从where OrderYear < right(year(getdate()),2)检索2017,然后使用getdate功能检索17。我敢肯定为什么你会发现这很危险,因为如果你的最新日期是1999年呢?

因此,通过过滤它们,我们可以看到每个RIGHT的最新年份...希望这会有所帮助。

Here是我建立的rextester测试,可以在您尝试使用时查询。

答案 2 :(得分:0)

我认为您的原始查询几乎完全是您需要的,除非您需要使用MAX(OrderID)而不是按照它进行分组。

declare @Something table
(
    orderid varchar(6)
)

insert @Something
(
    orderid
) values
('A04-05'), ('B81-02'), ('C02-01'),
('A01-01'), ('B95-01'), ('C99-05'),
('A02-02'), ('B06-07'), ('C03-02'),
('A98-06'), ('B10-01'), ('C17-01'),
('A78-07'), ('B02-03'), ('C15-03'),
('A79-01'), ('B02-01'), ('C78-06')

select max(orderid),
substring(orderid, 0, patindex('%[0-9]%', orderid)) as ordtype,
right(max(datepart(yyyy,'01/01/' + substring(orderid, patindex('%[0-9]-%', orderid) - 1, 2))),2) as year,
max(substring(orderid, patindex('%-[0-9]%', orderid) + 1, 2)) as ordnum
from myTable
where orderid is not null
group by substring(orderid, 0, patindex('%[0-9]%', orderid))
order by ordtype