2017-08-25 182 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') –