不同日期的差异最大值和最小值

时间:2015-04-22 14:09:07

标签: sql sql-server datetime max min

我会尽力解释这个问题。

以下代码执行以下操作:

  • 从ServiceLocation表中查找服务地址。
  • 查找服务类型(电力或水)。
  • 查找过去提取数据的天数。

一旦有了这个,就会计算出"每日使用量"通过从一天的最小仪表读数减去一天的最大仪表读数。

        (MAX(mr.Reading) - MIN(mr.Reading)) AS 'DaytimeUsage'

但是,我所缺少的是前一天的最大读数和当天的最小读数。在数学上,这看起来应该是这样的:

  • MAX(PriorDayReading) - MIN(ReadDateReading)

基本上,如果它可以追溯到5天,那么它应该按照以下内容执行:

  

服务地点|阅读日期|用法|

     

123 Main St | 2015年4月20日| 12 |
  123 Main St | 4/19/15 | 8 |
  123 Main St | 4/18/15 | 6 |
  123 Main St | 4/17/15 | 10 |
  123 Main St | 4/16/15 | 11 |

用法"用法"是' DaytimeUsage' +我失踪的用法(以及上面的问题)。例如,4/18/15将是' DaytimeUsage'在下面的查询PLUS中,从2015年4月17日读取MAX和从4/18/15读取MIN。

我不确定如何完成此操作或是否可行。

SELECT 
    A.ServiceAddress AS 'Service Address', 
    convert(VARCHAR(10),A.ReadDate,101) AS 'Date', 
    SUM(A.[DaytimeUsage]) AS 'Usage' 

FROM 
(
    SELECT
        sl.location_addr AS 'ServiceAddress', 
        convert(VARCHAR(10),mr.read_date,101) AS 'ReadDate', 
        (MAX(mr.Reading) - MIN(mr.Reading)) AS 'DaytimeUsage'
    FROM
        DimServiceLocation AS sl
        INNER JOIN FactBill AS fb ON fb.ServiceLocationKey = sl.ServiceLocationKey
        INNER JOIN FactMeterRead as mr ON mr.ServiceLocationKey = sl.ServiceLocationKey
        INNER JOIN DimCustomer AS c ON c.CustomerKey = fb.CustomerKey
    WHERE 
        c.class_name = 'Tenant'
        AND sl.ServiceLocationKey = @ServiceLocation
        AND mr.meter_type = @ServiceType
    GROUP BY 
        sl.location_addr, 
        convert(VARCHAR(10),
        mr.read_date,101)
) A

WHERE A.ReadDate >= GETDATE()-@Days 
GROUP BY A.ServiceAddress, convert(VARCHAR(10),A.ReadDate,101)
ORDER BY convert(VARCHAR(10),A.ReadDate,101) DESC

3 个答案:

答案 0 :(得分:1)

似乎你可以通过计算昨天的MAX和最大值之间的差异来解决这个问题。今天,不过这就是我接近它的方式。相对于任何给定日期,前一天再次加入同一个表格,并在内部查询中选择最大/最小值。此外,如果您将日期放在内部查询where子句中,您返回的数据集将更快更好。小。

SELECT 
A.ServiceAddress AS 'Service Address', 
  convert(VARCHAR(10),A.ReadDate,101) AS 'Date', 
  SUM(A.[TodayMax]) - SUM(A.[TodayMin]) AS 'Usage',
  SUM(A.[TodayMax]) - SUM(A.[YesterdayMax]) AS 'Usage with extra bit you want' 
FROM 
(
SELECT
    sl.location_addr AS 'ServiceAddress', 
    convert(VARCHAR(10),mr.read_date,101) AS 'ReadDate', 
    MAX(mrT.Reading) AS 'TodayMax',
    MIN(mrT.Reading) AS 'TodayMin',
    MAX(mrY.Reading) AS 'YesterdayMax',
    MIN(mrY.Reading) AS 'YesterdayMin',        
FROM
    DimServiceLocation AS sl
    INNER JOIN FactBill AS fb ON fb.ServiceLocationKey = sl.ServiceLocationKey
    INNER JOIN FactMeterRead as mrT ON mrT.ServiceLocationKey = sl.ServiceLocationKey
    INNER JOIN FactMeterRead as mrY ON mrY.ServiceLocationKey = s1.ServiceLocationKey
                                    AND mrY.read_date = mrT.read_date -1)
    INNER JOIN DimCustomer AS c ON c.CustomerKey = fb.CustomerKey
WHERE 
    c.class_name = 'Tenant'
    AND sl.ServiceLocationKey = @ServiceLocation
    AND mr.meter_type = @ServiceType
    AND convert(VARCHAR(10), mrT.read_date,101) >= GETDATE()-@Days 
GROUP BY 
    sl.location_addr, 
    convert(VARCHAR(10),
    mr.read_date,101)

) A
GROUP BY A.ServiceAddress, convert(VARCHAR(10),A.ReadDate,101)
ORDER BY convert(VARCHAR(10),A.ReadDate,101) DESC

答案 1 :(得分:0)

我不确定我是否完全理解你的数据库结构,但我可能有一个解决方案,所以随时编辑我的答案以适应或纠正任何错误。

这个想法是为表FactMeterRead使用两个别名。 mrY(Y as as yesterday)和mrT(T as Today)。并使用read_date限制区分它们。 但是我对你的表没有足够的理解来编写一个功能齐全的查询。我希望你能用这个例子得到这个想法。

SELECT
        sl.location_addr AS 'ServiceAddress', 
        convert(VARCHAR(10),mrT.read_date,101) AS 'ReadDate', 
        (MAX(mrY.Reading) - MIN(mrT.Reading)) AS 'DaytimeUsage'
    FROM
        DimServiceLocation AS sl
          INNER JOIN FactMeterRead as mrY ON mrY.ServiceLocationKey = sl.ServiceLocationKey
          INNER JOIN FactMeterRead as mrT ON mrT.ServiceLocationKey = sl.ServiceLocationKey
    WHERE mrY.read_date=DATE_SUB(mrT.read_date,1 DAY)

答案 2 :(得分:0)

如果您位于sql server 2005之上,则可以使用APPLY运算符。以下是文档的链接。 https://technet.microsoft.com/en-us/library/ms175156(v=sql.105).aspx APPLY操作有两种形式:OUTER APPLY AND CROSS APPLY - OUTER的工作方式类似于左连接,而CROSS的工作方式类似于内连接。它们允许您为返回的每一行运行一次查询。我设置了你自己想要做的样本,这是它,我希望它有所帮助。

http://sqlfiddle.com/#!6/fdb3f/1

CREATE TABLE SequencedValues (
  Location varchar(50) NOT NULL,
  CalendarDate datetime NOT NULL,
  Reading int
  )

INSERT INTO SequencedValues (
  Location,
  CalendarDate,
  Reading
  )
 SELECT
   'Address1',
   '4/20/2015',
   10
UNION SELECT
   'Address1',
   '4/19/2015',
   9
UNION SELECT
   'Address1',
   '4/19/2015',
   20
UNION SELECT
   'Address1',
   '4/19/2015',
   25
UNION SELECT
   'Address1',
   '4/18/2015',
   8
UNION SELECT
   'Address1',
   '4/17/2015',
   7
UNION SELECT
   'Address2',
   '4/20/2015',
   100
UNION SELECT
   'Address2',
   '4/20/2015',
   111
UNION SELECT
   'Address2',
   '4/19/2015',
   50
UNION SELECT
   'Address2',
   '4/19/2015',
   65


SELECT DISTINCT 
    sv.Location,
    sv.CalendarDate,
    sv_dayof.MINDayOfReading,
    sv_daybefore.MAXDayBeforeReading
FROM SequencedValues sv
OUTER APPLY (
    SELECT MIN(sv_dayof_inside.Reading) AS MINDayOfReading
    FROM SequencedValues sv_dayof_inside
    WHERE sv.Location = sv_dayof_inside.Location
    AND sv.CalendarDate = sv_dayof_inside.CalendarDate
    ) sv_dayof
OUTER APPLY (
    SELECT MAX(sv_daybefore_max.Reading) AS MAXDayBeforeReading
    FROM SequencedValues sv_daybefore_max
    WHERE sv.Location = sv_daybefore_max.Location
    AND sv_daybefore_max.CalendarDate IN (
        SELECT TOP 1 sv_daybefore_inside.CalendarDate
        FROM SequencedValues sv_daybefore_inside
        WHERE sv.Location = sv_daybefore_inside.Location
        AND sv.CalendarDate > sv_daybefore_inside.CalendarDate
        ORDER BY sv_daybefore_inside.CalendarDate DESC
        )
    ) sv_daybefore
ORDER BY
    sv.Location,
    sv.CalendarDate DESC