2017-08-25 161 views
0

我有一个SQL Server 2016中的事务表,其中有一列名为mthweekyr的列,其中列中的每一行都以字符串形式表示月份编号,月份的星期编号和事务的年份,其中周数由每月的第7天确定。SQL Server按日期排序

例如,如果交易日期为:2018-09-28,则这将显示为9-4-2018

问题是原始交易日期列实际上不在表格中,我想按mthweekyr列对这些交易排序,但由于此列不是日期类型,因此无法这样做,它是一个字符串类型。 (我不制作桌子,我只是用它们!)

关于如何继续的任何建议?

谢谢。

+5

所以,如果这里真正需要的是排序(而不是转换为日期),然后将该字符串重新格式化为'YYYY-MM-W#',这将允许您按照字典顺序进行排序并获取您的预期的结果。那就是我专注于时间的地方。 – JNevill

+0

@JNevill伟大的建议,谢谢。 T-SQL中的语法是什么? –

+0

除此之外:您可能需要使用适当的数据类型向表中添加_persisted计算列_ '日期',以保持价值。它也可以被索引。这应该让桌子变得更容易。 – HABO

回答

2

使用JNevill的建议,你可以利用PARSENAME。

declare @Date varchar(20) = '9-4-2018' 
select PARSENAME(replace(@Date, '-', '.'), 1) + '-' + right('00' + PARSENAME(replace(@Date, '-', '.'), 3), 2) + '-' + right('00' + PARSENAME(replace(@Date, '-', '.'), 2), 2) 

这将返回2018年9月4日

你也可以做一些字符串操作但开始变得相当繁琐。

+0

祝福你把它放在一起。我采取了刺,但我没有永远写tsql和字符串解析让我的头旋转。 – JNevill

+0

嗨,谢谢。我看到你只宣布了一个日期的@date。如果出于好奇他们只有一列,你会怎么做? –

+0

@JNevill同意了。弄乱弦是丑陋的。这正是我为此选择了PARSENAME的快捷方式。 :) –

3

这里的另一种方式......

declare @table table(mthweekyr varchar(10)) 
insert into @table 
values 
('9-4-2018'), 
('8-4-2018'), 
('9-5-2018'), 
('7-5-2018'), 
('7-4-2018'), 
('9-5-2017'), 
('9-4-2017') 

select * 
from @table 
order by 
    cast(right(mthweekyr,4) as int)       --order by year first 
    ,cast(left(mthweekyr,charindex('-',mthweekyr)-1) as int) --order by month. Works for single or double digit months 
    ,left(right(mthweekyr,6),1)        --order by week number which is always a single digit, since it's the week number of the month not the year. 
+0

这也适用。事实上,这可能比我的解决方案更容易理解(代码少)。应该产生几乎相同的执行计划。从我+1。 –

+0

我意识到我必须投入月份和年份,因为多位数字会搞乱订购。 *应该*现在工作。谢谢@SeanLange – scsimon

+0

看到我的答案。 ---你可以简单地使用隐式转换为日期。我怀疑你是在过度使用它 –

1

显然不是最有效的,我知道,但蛮力它...

order by substring(@theStr, len(@theStr) - 4 + 1, 4) 
       + substring(@thestr, charindex('-',@Thestr)+1,1) 
       + right('00' + substring(@thestr, 1, charindex('-',@Thestr)-1),2) 

这里是如何通过作品去那里:

declare @thestr varchar(255) = '9-4-2018' 

Declare @SortStr as Varchar(255) 

--year 
Select @SortStr = substring(@theStr, len(@theStr) - 4 + 1, 4) 
print @Sortstr 
--day 
Select @SortStr = right('00' + substring(@thestr, 1, charindex('-',@Thestr)-1),2) 
print @sortStr 

--week 
Select @SortStr = substring(@thestr, charindex('-',@Thestr)+1,1) 
print @sortStr 

Select @SortStr = substring(@theStr, len(@theStr) - 4 + 1, 4) 
       + substring(@thestr, charindex('-',@Thestr)+1,1) 
       + right('00' + substring(@thestr, 1, charindex('-',@Thestr)-1),2) 

会产生此输出

2018 
09 
4 
2018409 
1

由于您知道日期散列算法,您可以将原始日期恢复到新列中,然后对其进行排序。喜欢的东西:

SELECT *, CONVERT(datetime2(1), 
    RIGHT(@mthweekyr, 4) + '-' + 
    LEFT(@mthweekyr, CHARINDEX('-', @mthweekyr) - 1) + '-' + 
    SUBSTRING(@mthweekyr, CHARINDEX('-', @mthweekyr) + 1, 
     CHARINDEX('-', @mthweekyr, CHARINDEX('-', @mthweekyr) + 1) 
      - CHARINDEX('-', @mthweekyr) - 1)) AS EstimatedDate 
FROM theTable 
ORDER BY EstimatedDate 

UPDATE

所以上面是长,困难的方式。

一个更明智的方法是将重任提升到SQL引擎并使用CONVERT function的第三个参数,该参数指定输入的样式。由于mthweekyr基本上代表的mm-d-yyyy一个美国风格,查询将看起来像:

SELECT *, CONVERT(datetime2(1), mthweekyr, 110) AS EstimatedDate 
    FROM theTable 
    ORDER BY EstimateDate 
3

迟到的回答,但也许更薄的替代品。

您可以简单地使用MDY的隐式转换日期

declare @table table(mthweekyr varchar(10)) 
insert into @table 
values 
('9-4-2018'), 
('8-4-2018'), 
('9-5-2018'), 
('7-5-2018'), 
('7-4-2018'), 
('9-5-2017'), 
('9-4-2017'), 
('10-4-2017'), -- added 2 digit month 
('10-5-2017') -- added 2 digit month 

Select * 
From @table 
Order By convert(date,mthweekyr) 

返回

mthweekyr 
9-4-2017 
9-5-2017 
10-4-2017 
10-5-2017 
7-4-2018 
7-5-2018 
8-4-2018 
9-4-2018 
9-5-2018 
+1

从技术上讲,现在我也会想起它 – scsimon

+0

嗯。太棒了!那么,什么是_implicit conversion_反正呢?该文档说,默认格式,'CONVERT'假定是'mon dd yyyy hh:miAM(或PM)'。是_implicit == default_呢? –

+0

@BozhidarStoinev有许多这样的隐式转换。例如:select try_convert(datetime,'Aug 26,2017 9:00 am') ,try_convert(datetime,'August 26,2017 9:00 am') ,try_convert(datetime,'20170827') \t,try_convert(datetime ,'08/27/17') –