执行非常特定的SQL查询以将数据放入不同格式的问题

时间:2009-03-18 14:34:29

标签: sql sql-server sql-server-2005

我在处理需要查询并重新格式化为另一个表的SQL表时出于报告目的而遇到一些麻烦。这是初始表:

id               int, 
logtimestamp    datetime, 
serialnumber    varchar(255), 
robotid         int, 
amountconsumed  float 

robotid仅为1到4.每隔15-20分钟,会添加新行。通常,每个机器人都会报告一个序列号,但情况并非总是如此。序列号可以定期重复。 (这只在测试时发生,但可能会发生。)

我的目标是在给定的一天中计算每个robotid的消耗量,并将这些值放在一个如下所示的结果表中:

id              int, 
logtimestamp   datetime,
robot1consumed float, 
robot2consumed float, 
robot3consumed float, 
robot4consumed float 

我无法创建一个能够准确考虑

事实的查询
  • 可能存在重复的序列号
  • 并非每个序列号都有4个robotid(如果当天不存在robotid,则该值应设置为0)。

这是我到目前为止所提出的(@startDate和@endDates):

SELECT 
    timestamp=dateadd(month,((Year(R1.logtimestamp)-1900)*12)+Month(R1.logtimestamp)-1,Day(R1.logtimestamp)-1),
    sum(R1.robot1consumed ), 
    sum(R2.robot1consumed ), 
    sum(R3.robot1consumed ), 
    sum(R4.robot1consumed )
FROM 
    Robot_Consumption R1, 
    Robot_Consumption R2, 
    Robot_Consumption R3, 
    Robot_Consumption R4
WHERE
   R1.robotid = '1' 
   AND R2.robotid = '2' 
   AND R3.robotid = '3' 
   AND R4.robotid = '4' 
   AND R1.logtimestamp BETWEEN @startDate AND @endDate 
   AND R1.serialnumber = R2.serialnumber 
   AND R1.serialnumber = R3.serialnumber 
   AND R1.serialnumber = R4.serialnumber 
GROUP BY 
   Year(R1.logtimestamp), Month(R1.logtimestamp), Day(R1.logtimestamp)

除了上面列出的限制,这个工作正常。是否有任何建议在给定先前列出的约束条件的情况下将此查询更改为有效?

1 个答案:

答案 0 :(得分:2)

SELECT  '0000-00-00' + INTERVAL dte DAY AS robot_date,
        id,
        SUM(amountconsumed)
FROM    (
        SELECT 1 AS id
        UNION ALL
        SELECT 2
        UNION ALL
        SELECT 3
        UNION ALL
        SELECT 4
        ) r
-- this is to select all robotids
JOIN
        (
        SELECT  DISTINCT TO_DAYS(logtimestamp) AS dte
        FROM    Robot_Consumption
        WHERE   logtimestamp BETWEEN @startDate AND @endDate 
        ) rd
-- this is to select all days that have any records
LEFT OUTER JOIN
        RobotConsumption rc
ON      rc.robotid = r.id
        AND rc.logtimestamp BETWEEN '0000-00-00' + INTERVAL dte DAY AND '0000-00-00' + INTERVAL dte + 1 DAY 
WHERE   NOT EXISTS
        (
        SELECT  1
        FROM    Robot_Consumption rci
        WHERE   rci.robotid = rc.robotid
                AND rci.serial_number = rc.serial_number
                AND rci.id < rc.id
        )
-- this is to handle duplicates
GROUP BY
        dte, id

如果您需要连续拍摄结果,请使用:

SELECT  '0000-00-00' + INTERVAL dte DAY AS robot_date,
        COALESCE(
        (
        SELECT  SUM(amountconsumed)
        FROM    Robot_Consumption rc
        WHERE   rc.robotid = 1
                AND rc.logtimestamp BETWEEN '0000-00-00' + INTERVAL dte DAY AND '0000-00-00' + INTERVAL dte + 1 DAY
                AND NOT EXISTS
                (
                SELECT  1
                FROM    Robot_Consumption rci
                WHERE   rci.robotid = rc.robotid
                        AND rci.serial_number = rc.serial_number
                        AND rci.id < rc.id
                )
        ), 0) AS robot1consumed,
        COALESCE(
        (
        SELECT  SUM(amountconsumed)
        FROM    Robot_Consumption rc
        WHERE   rc.robotid = 2
                AND rc.logtimestamp BETWEEN '0000-00-00' + INTERVAL dte DAY AND '0000-00-00' + INTERVAL dte + 1 DAY
                AND NOT EXISTS
                (
                SELECT  1
                FROM    Robot_Consumption rci
                WHERE   rci.robotid = rc.robotid
                        AND rci.serial_number = rc.serial_number
                        AND rci.id < rc.id
                )
        ), 0) AS robot2consumed,
        COALESCE(
        (
        SELECT  SUM(amountconsumed)
        FROM    Robot_Consumption rc
        WHERE   rc.robotid = 3
                AND rc.logtimestamp BETWEEN '0000-00-00' + INTERVAL dte DAY AND '0000-00-00' + INTERVAL dte + 1 DAY
                AND NOT EXISTS
                (
                SELECT  1
                FROM    Robot_Consumption rci
                WHERE   rci.robotid = rc.robotid
                        AND rci.serial_number = rc.serial_number
                        AND rci.id < rc.id
                )
        ), 0) AS robot3consumed,
        COALESCE(
        (
        SELECT  SUM(amountconsumed)
        FROM    Robot_Consumption rc
        WHERE   rc.robotid = 4
                AND rc.logtimestamp BETWEEN '0000-00-00' + INTERVAL dte DAY AND '0000-00-00' + INTERVAL dte + 1 DAY
                AND NOT EXISTS
                (
                SELECT  1
                FROM    Robot_Consumption rci
                WHERE   rci.robotid = rc.robotid
                        AND rci.serial_number = rc.serial_number
                        AND rci.id < rc.id
                )
        ), 0) AS robot4consumed,
FROM    (
        SELECT  DISTINCT TO_DAYS(logtimestamp) AS dte
        FROM    Robot_Consumption
        WHERE   logtimestamp BETWEEN @startDate AND @endDate 
        ) rd