[英]Convert number of years and months into number of months
我的表包含一個列,其中包含一個值,該值表示以年和月為單位的時間段,換句話說:
ID PERIOD
1 1Y
2 1Y1M
3 11M
4 5Y2M
在執行選擇語句時如何將其轉換/計算為月數? 處理只有 'Y' 或只有 'M' 的值很容易,但不知道如何處理上面示例中的 ID 2 和 ID 4。
如果我選擇以上所有內容,select 語句的結果將是:
12
13
11
62
您可以使用
SUBSTRING(period, 1, CHARINDEX('Y', Period) - 1)
只得到 Y 之前的數字,然后乘以 12。
對於 Y 不存在的情況可以用 CASE 處理
所以像這樣:
SELECT CASE WHEN Period LIKE '%Y' THEN
CAST(SUBSTRING(period, 1, CHARINDEX('Y', Period) - 1)) * 12
+
CAST(REPLACE(SUBSTRING(period, CHARINDEX('Y', Period)),'M',''))
ELSE
CAST(REPLACE(period,'M',''))
您可以執行以下操作
SELECT *, TRY_CAST(REPLACE(Y, 'Y', '') AS INT) * 12 +
TRY_CAST(REPLACE(REPLACE(Period, Y, ''), 'M', '') AS INT)
FROM
(
VALUES
(1, '1Y'),
(2, '1Y1M'),
(3, '11M'),
(4, '5Y2M'),
(5, 'Whatever')
) T(Id, Period)
CROSS APPLY
(
VALUES
(LEFT(Period, CHARINDEX('Y', Period)))
) CI(Y)
返回:
+----+----------+----+------------------+
| Id | Period | Y | (No column name) |
+----+----------+----+------------------+
| 1 | 1Y | 1Y | 12 |
| 2 | 1Y1M | 1Y | 13 |
| 3 | 11M | | 11 |
| 4 | 5Y2M | 5Y | 62 |
| 5 | Whatever | | |
+----+----------+----+------------------+
這是另一種方式
SELECT Id,
Period,
(REPLACE(Years, 'Y', '') * 12) + REPLACE(Months, 'M', '') TotalMonths
FROM
(
VALUES
(1, '1Y'),
(2, '1Y1M'),
(3, '5M'),
(4, '10Y11M'),
(5, 'Whatever write Y and M')
) T(Id, Period)
CROSS APPLY
(
VALUES
(
LEFT(Period, CHARINDEX('Y', Period)), REPLACE(REPLACE(Period, 'Y', ''), 'M', '')
)
) TT(Years, Value)
CROSS APPLY
(
VALUES
(
REPLACE(Period, Years, '')
)
) TTT(Months)
WHERE TRY_CAST(TT.Value AS INT) IS NOT NULL;
沒有那么多可能。 建立參考表:
select identity(int) as period_id, v.*
into periods p
from (values ('1M', 1),
('2M', 2),
. . .
('1Y', 12),
('1Y1M', 13),
. . .
) v(period, months);
這可以使用電子表格輕松構建。 甚至是遞歸 CTE。
我建議這樣做的原因很嚴重:你不應該像這樣對字符串表示進行計算。 這些值應被視為對表的外鍵引用。 而且,事實上,他們應該使用主鍵(標識列)而不是字符串。
在修復此問題時,您可能會發現格式錯誤的字符串。 從數據質量的角度來看,這是一件好事。
另一種選擇
select id, (parsename (clean,2) * 12) + (parsename(clean,1)) as months
from t
cross apply (select replace(replace(case when charindex('M', period)=0 then period + '0M'
when charindex('Y', period)=0 then '0Y' + period
else period end,'M',''),'Y','.') as clean) t2
輸出
+----+--------+
| id | months |
+----+--------+
| 1 | 12 |
| 2 | 13 |
| 3 | 11 |
| 4 | 62 |
+----+--------+
我認為這樣的事情會起作用
數據
drop table if exists #tTEST;
go
select * INTO #tTEST from (values
(1, '1Y'),
(2, '1Y1M'),
(3, '11M'),
(4, '5Y2M')) V(ID, [Period]);
詢問
select
t.*,
isnull(substring(t.[Period], 1, nullif(y_ndx, 0)-1)*12, 0) +
isnull(substring(t.[Period], y_ndx+1, nullif(m_ndx, 0)-isnull(y_ndx, 0)-1),0) answer
from #tTEST t
cross apply (select len(t.[Period]) p_len,
CHARINDEX('Y', t.[Period]) y_ndx,
CHARINDEX('M', t.[Period]) m_ndx) ndx;
結果
ID Period answer
1 1Y 12
2 1Y1M 13
3 11M 11
4 5Y2M 62
在標量值函數下面試試這個以獲得周期值
CREATE FUNCTION [dbo].[fn_sum](
@delimited NVARCHAR(MAX),
@delimiter NVARCHAR(100)
) RETURNS INT
AS
BEGIN
DECLARE @value INT
set @delimited=replace(replace(@delimited,'M','M,'),'Y','Y,')
DECLARE @xml XML
SET @xml = N'<t>' + REPLACE(@delimited,@delimiter,'</t><t>') + '</t>'
SELECT @value=sum(cast(replace(replace(r.value('.','Nvarchar(MAX)'),'M',''),'Y','') AS INT)
* CASE WHEN right(r.value('.','Nvarchar(MAX)'),1)='M' THEN 1 ELSE 12 END)
FROM @xml.nodes('/t') AS records(r)
RETURN @value
END
檢查以下示例輸出
DECLARE @tblPeriod AS TABLE(id VARCHAR(100),period VARCHAR(100))
INSERT INTO @tblPeriod(id,period) VALUES(1,'1Y'),(2,'1Y1M'),(3,'11M'),(4,'5Y2M')
SELECT id,period,dbo.[fn_sum](period,',') AS period_value FROM @tblPeriod a
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.