2017-10-17 105 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