简化SQL代码

时间:2017-10-17 11:33:29

标签: sql sql-server

我做了一些我希望在一个表中组合的单个查询。每个查询检索F1,F2,F3的日期和值以及总数。

我想知道我是否可以使这个查询更容易,特别是如何实现这一点。所以更少的代码,但实现相同的事情。特别是当我想稍后将其扩展到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

如果我尝试条件聚合。它给出了所有deltavalues的总和。但它应该只对具有相同日期的值求和。

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.

3 个答案:

答案 0 :(得分: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没有别名,我不知道它来自哪个表。

答案 1 :(得分: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

答案 2 :(得分: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;

希望它有所帮助!