2017-10-17 151 views
2

我做了一些個人查詢,我想合併在一張表中。每個查詢檢索F1,F2,F3和總數的日期和值。簡化SQL代碼

我想知道我是否可以使這個查詢更容易,尤其是如何實現這一點。所以更少的代碼,但實現相同的事情。特別是當我想稍後將其擴展到F20時。

查詢只是將數據每15分鐘添加一次。

2017-09-20 10:15 |49.0000|f1.1 
2017-09-20 10:15 |40.0000|f1.2 
2017-09-20 10:15 |11.0000|f1.3 
2017-09-20 10:15 |0.0000|f1.4  
2017-09-20 10:15 |0.0000 |f1.5 
2017-09-20 10:15 |0.0000 |f1.6 

查詢給我時間的總和。 2017-09-20 10:15

如果我嘗試條件聚合。它給出了所有delta值的總和。但它應該只將相同日期的值相加。

declare @days int 
set @days = -165 

SELECT a.Date, a.F1, b.F2, c.F3, d.Total 
FROM 
(SELECT rv.Date, sum(rv.value_num) as F1 
FROM   dbo.Channels c INNER JOIN 
          (SELECT  rv.*, TRY_CONVERT(numeric(20, 4), rv.Value) AS value_num, (LEFT(TRY_CONVERT(datetime2(0), rv.Timestamp), 16)) AS Date 
          FROM   dbo.RecordedValues rv) rv ON c.SourceId = rv.SourceId AND c.Id = rv.ChannelId 
WHERE c.Tag LIKE N'%F1%' 
AND Timestamp BETWEEN DATEADD(day,@days,GETDATE()) AND GETDATE() 
GROUP BY rv.Date 
) as a, 

(SELECT rv.Date, sum(rv.value_num) as F2 
FROM   dbo.Channels c INNER JOIN 
          (SELECT  rv.*, TRY_CONVERT(numeric(20, 4), rv.Value) AS value_num, (LEFT(TRY_CONVERT(datetime2(0), rv.Timestamp), 16)) AS Date 
          FROM   dbo.RecordedValues rv) rv ON c.SourceId = rv.SourceId AND c.Id = rv.ChannelId 
WHERE c.Tag LIKE N'%F2%' 
AND Timestamp BETWEEN DATEADD(day,@days,GETDATE()) AND GETDATE() 
GROUP BY rv.Date 
) as b, 

( SELECT rv.Date, sum(rv.value_num) as F3 
FROM   dbo.Channels c INNER JOIN 
          (SELECT  rv.*, TRY_CONVERT(numeric(20, 4), rv.Value) AS value_num, (LEFT(TRY_CONVERT(datetime2(0), rv.Timestamp), 16)) AS Date 
          FROM   dbo.RecordedValues rv) rv ON c.SourceId = rv.SourceId AND c.Id = rv.ChannelId 
WHERE c.Tag LIKE N'%F3%' 
AND Timestamp BETWEEN DATEADD(day,@days,GETDATE()) AND GETDATE() 
GROUP BY rv.Date 

) as c, 

(SELECT rv.Date, sum(rv.value_num) as Total 
FROM   dbo.Channels c INNER JOIN 
          (SELECT  rv.*, TRY_CONVERT(numeric(20, 4), rv.Value) AS value_num, (LEFT(TRY_CONVERT(datetime2(0), rv.Timestamp), 16)) AS Date 
          FROM   dbo.RecordedValues rv) rv ON c.SourceId = rv.SourceId AND c.Id = rv.ChannelId 
WHERE c.Tag LIKE N'%F%' 
AND Timestamp BETWEEN DATEADD(day,@days,GETDATE()) AND GETDATE() 
GROUP BY rv.Date 

) as d 
where a.Date = b.Date 
AND b.Date = c.Date 
AND c.Date = d.Date 

這是目前如何給我的價值觀:

RecDate    F1 |F2 |F3 |Total 
2017-09-20 10:15| 100 |200|100|400 
2017-09-20 10:30| 150 |200|150|500 
2017-09-20 10:45| 125 |200|100|425 
2017-09-20 11:00| 110 |210|110|440 
etc. 
+1

即使您簡化查詢,性能也會變差*,因爲像LIKE'%F1%'這樣的每個子句都會強制進行全表掃描。 'tag'包含什麼? –

+2

如果您可以提供原始數據的樣本,以及您期望輸出的樣子,這將是一個很大的幫助。看看[how-to-ask](http://stackoverflow.com/help/how-to-ask)頁面,瞭解一些提煉你的問題的提示。 – gmiley

+0

爲什麼'(LEFT(TRY_CONVERT(datetime2(0),rv.Timestamp),16)''你將* something *轉換爲datetime2然後轉換爲一個字符串,然後將其截斷?爲什麼?是否要將某些東西轉換爲'日期'也許?'時間戳'的類型是什麼? –

回答

0

在你當前的查詢,你正在做的交叉連接這是最糟糕的表現明智的所有表。相反,使用Case..When,因爲它似乎是你的問題的完美方法。

由於我不知道的模式和時間戳和日期的轉換背後的原因,我可以建議的是下面的查詢:

declare @days int 
set @days = -165 

SELECT rv.Date, 
sum(case when c.Tag LIKE N'%F1%' then rv.value_num else 0 end) as F1, 
sum(case when c.Tag LIKE N'%F2%' then rv.value_num else 0 end) as F2, 
sum(case when c.Tag LIKE N'%F3%' then rv.value_num else 0 end) as F3, 
sum(case when c.Tag LIKE N'%F%' then rv.value_num else 0 end) as total, 
FROM dbo.Channels c 
INNER JOIN 
     (SELECT rv.*, TRY_CONVERT(numeric(20, 4), rv.Value) AS value_num, 
(LEFT(TRY_CONVERT(datetime2(0), rv.Timestamp), 16)) AS Date 
     FROM dbo.RecordedValues rv) rv 
ON c.SourceId = rv.SourceId AND c.Id = rv.ChannelId 
WHERE 
rv.Timestamp BETWEEN DATEADD(day,@days,GETDATE()) AND GETDATE() 
GROUP BY rv.Date; 

希望它能幫助!

+0

我試過了,但它不算總和。它不會給我的價值,就像我現在寫在我的帖子裏一樣。我每分鐘得到一個奇怪的值爲零和每15分鐘。我的原始數據每15分鐘只給出一個值。 –

+0

你可以在sqlfiddle或rextester上創建測試數據嗎? –

+0

我添加了case和else的部分。現在就試試。 –

0

可以使用條件聚合,簡化驗證碼:

SELECT rv.date, 
     SUM(CASE WHEN t.Tag LIKE N'%F1%' THEN rv.value_num ELSE 0 END) as f1, 
     SUM(CASE WHEN t.Tag LIKE N'%F2%' THEN rv.value_num ELSE 0 END) as f2, 
     SUM(CASE WHEN t.Tag LIKE N'%F3%' THEN rv.value_num ELSE 0 END) as f3, 
     SUM(CASE WHEN t.Tag LIKE N'%F%' THEN rv.value_num ELSE 0 END) as total 
FROM dbo.channels t 
JOIN (SELECT rv.*, TRY_CONVERT(numeric(20, 4), rv.Value) AS value_num, (LEFT(TRY_CONVERT(datetime2(0), rv.Timestamp), 16)) AS Date      
     FROM dbo.RecordedValues rv 
     WHERE rv.Timestamp BETWEEN DATEADD(day,@days,GETDATE()) AND GETDATE()) rv 
ON (c.SourceId = rv.SourceId AND c.Id = rv.ChannelId) 
GROUP BY rv.Date 

這樣,你只掃描表一次。

請注意,您應該別名使用每個列 - >Timestamp不是別名,我不知道它來自哪個表。

+0

它來自RecordedValues。所以它應該像rv.Timestamp對嗎? –

+0

準確@IonK。沒有寫錯,但你應該爲所有人使用別名,或使用別名爲非一致:) – sagi

+0

我試過了,但它不起作用。它現在不會在每個時間範圍內累加。 –

0

我想你只需要有條件的聚集

SELECT rv.Date, 
     SUM(CASE WHEN c.Tag LIKE N'%F%' THEN rv.value_num END) as Total, 
     SUM(CASE WHEN c.Tag LIKE N'%F1%' THEN rv.value_num END) as F1, 
     SUM(CASE WHEN c.Tag LIKE N'%F2%' THEN rv.value_num END) as F2, 
     SUM(CASE WHEN c.Tag LIKE N'%F3%' THEN rv.value_num END) as F3 
FROM   dbo.Channels c 
INNER JOIN (
    SELECT rv.*, 
      TRY_CONVERT(numeric(20, 4), rv.Value) AS value_num, 
      LEFT(TRY_CONVERT(datetime2(0), rv.Timestamp), 16) AS Date 
    FROM dbo.RecordedValues rv 
) rv ON c.SourceId = rv.SourceId AND c.Id = rv.ChannelId 
AND Timestamp BETWEEN DATEADD(day,@days,GETDATE()) AND GETDATE() 
GROUP BY rv.Date