проблема выполнения очень специфического запроса SQL для размещения данных в другом формате - PullRequest
0 голосов
/ 18 марта 2009

У меня возникли проблемы при работе с таблицей SQL, которую необходимо запросить и переформатировать в другую таблицу для составления отчетов. Вот исходная таблица:

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

robotid только от 1 до 4. Каждые 15-20 минут добавляются новые строки. Обычно каждый робот сообщает об одном серийном номере, но это не всегда так. Периодически серийный номер может иметь дубликаты. (Это происходит только при тестировании, но может случиться.)

Моя цель - сложить сумму, потребляемую для каждого робота в данный день, и поместить эти значения в таблицу результатов, которая выглядит следующим образом:

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

У меня возникли проблемы при создании запроса, который будет точно учитывать тот факт, что

  • могут существовать повторяющиеся серийные номера
  • не каждый серийный номер будет иметь все 4 роботида (если робот не существует в течение дня, то значение должно быть установлено на 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 Ответ

2 голосов
/ 18 марта 2009
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
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...