SQL SELECT одно значение для нескольких таблиц

Я использую 6 таблиц для измерения датчика.

DEVICES
id imei        name
1  123456789   device1

BMP085
id deviceId date        time     pressure altitude tempC tempF
1  1        2014-02-21  20:01:02 000.00   000.00   00.00 00.00

GPS
id deviceId date       time     latitude longitude timeUtc  timeFix  altitude eps   epx   epv   ept   speed climb track mode satellites
1  1        2014-02-21 20:01:02 0.000000 0.000000  00:00:00 00:00:00 0.00     0.000 0.000 0.000 0.000 0.000 0.000 0.00  0    0

HIH6130
id deviceId date       time     humidity tempC tempF
1  1        2014-02-21 20:01:02 00.00    00.00 00.00

MINIMU9V2
id deviceId date        time    heading tempC tempF xAngle yAngle zAngle xAccel yAccel zAccel xMagn  yMagn  zMagn
1  1        2014-02-21 20:01:02 000.00  00.00 00.00 00.000 00.000 00.000 00.000 00.000 00.000 00.000 00.000 00.000

RASPI
id deviceId date       time     tempC tempF
1  1        2014-02-21 20:01:02 00.00 00.00

Я хотел бы выбрать все соответствующие наборы данных таблиц BMP085, GPS, HIH6130, MINIMU9V2 и RASPI, которые имеют deviceId = 1. Предполагается, что будут отображаться только наборы данных для этого устройства. Кроме того, я хотел бы выбрать все совпадающие наборы данных таблиц BMP085, GPS, HIH6130, MINIMU9V2 и RASPI, которые имеют дату = 2014-02-21 и время >= 20:01:00 И ‹= 20:01:30.

Моя текущая инструкция SQL выглядит так:

SELECT t1.imei, t1.name, 
    t2.date, t2.time, t2.pressure, t2.altitude, t2.tempC, t2.tempF,
    t3.latitude, t3.longitude, t3.timeUtc, t3.timeFix, t3.altitude, t3.eps, t3.epx, t3.epv, t3.ept, t3.speed, t3.climb, t3.track, t3.mode, t3.satellites,
    t4.humidity, t4.tempC, t4.tempF,
    t5.heading, t5.tempC, t5.tempF, t5.xAngle, t5.yAngle, t5.zAngle, t5.xAccel, t5.yAccel, t5.zAccel, t5.xMagn, t5.yMagn, t5.zMagn,
    t6.tempC, t6.tempF
    FROM hab_DEVICES t1
    LEFT JOIN hab_BMP085 t2 ON t1.id = t2.deviceId
    LEFT JOIN hab_GPS t3 ON t1.id = t3.deviceId
    LEFT JOIN hab_HIH6130 t4 ON t1.id = t4.deviceId
    LEFT JOIN hab_MINIMU9V2 t5 ON t1.id = t5.deviceId
    LEFT JOIN hab_RASPI t6 ON t1.id = t6.deviceId       
    WHERE t1.id = 1
    AND t2.date = '2014-02-21'
    AND t2.date = t3.date
    AND t2.date = t4.date
    AND t2.date = t5.date
    AND t2.date = t6.date
    AND t2.time >= '20:01:00'
    AND t2.time <= '20:01:30'
    AND t2.time = t3.time
    AND t2.time = t4.time
    AND t2.time = t5.time
    AND t2.time = t6.time

Результат неверен, так как он отображает несколько результатов для одного заданного момента времени вместо одного результата. Кроме того, производительность довольно плохая.

Вот моя скрипка: http://sqlfiddle.com/#!2/639c05/1/ 0

Любая помощь приветствуется.


person Daniel    schedule 16.03.2014    source источник
comment
Не могли бы вы написать sqlfiddle (sqlfiddle.com) с некоторыми вашими данными и описаниями ваших таблиц? это очень поможет найти решение   -  person Federico J.    schedule 16.03.2014
comment
Вот моя скрипка, уже включающая ВНУТРЕННЕЕ СОЕДИНЕНИЕ, предложенное Chococroc: sqlfiddle.com/#! 2/639c05/1/0   -  person Daniel    schedule 16.03.2014
comment
Должны ли даты как-то быть связаны друг с другом?   -  person Strawberry    schedule 16.03.2014
comment
Я записываю данные датчиков каждые 15 секунд для всех датчиков одновременно, поэтому я хотел бы получить набор данных, который был установлен в определенный момент времени для всех датчиков.   -  person Daniel    schedule 16.03.2014
comment
Хорошо, я справился, проблема заключалась в ключе соединения: вам также нужно включить время. Проверьте обновление в ответе, XD   -  person Federico J.    schedule 17.03.2014
comment
блестяще! ваше решение помогло!   -  person Daniel    schedule 17.03.2014


Ответы (1)


Вы уверены, что результаты вашего набора данных неверны? Поскольку вы присоединяетесь ко многим таблицам, более чем вероятно, что ваши результаты дублируются в ваших таблицах, из-за чего ваши строки отображаются более одного раза.

Для проверки:

SELECT t1.imei, t1.name, 
       t2.date, t2.time, t2.pressure, t2.altitude, t2.tempC, t2.tempF
FROM hab_DEVICES t1
LEFT JOIN hab_BMP085 t2 ON ( t1.id = t2.deviceId AND t1.id = 1 )
WHERE   t2.date = '2014-02-21'
    AND t2.time >= '20:01:00'
    AND t2.time <= '20:01:30'

И запишите количество строк, которые вы получите (возможно, вам будет полезно использовать SELECT count(1) AS total вместо полей, которые сразу дадут вам число, ;D). Когда закончите, добавьте другую таблицу и повторите. В конце вы увидите, какая таблица отвечает за дублирование ваших данных. Когда вы получите это, вы сможете узнать, что вы должны сделать, чтобы исправить это.

Что касается производительности, LEFT JOIN работает довольно медленно, если бы вы могли использовать INNER JOIN, вы бы быстро получили свои результаты. Вы также должны проверить индексы, которые есть в ваших таблицах.

ОБНОВИТЬ

Хорошо, я нашел проблему: Ваш ключ JOIN - это не только id, это еще и время! Если вы присоединитесь только по идентификатору, все таблицы будут умножать выбранные значения, но если вы присоединитесь по идентификатору, дате и времени, вы получите правильные строки. Измените свой SQL, чтобы он был:

SELECT t1.imei, t1.name, 
        t2.date, t2.time, t2.pressure, t2.altitude, t2.tempC, t2.tempF,
        t3.latitude, t3.longitude, t3.timeUtc, t3.timeFix, t3.altitude, t3.eps, t3.epx, t3.epv, t3.ept, t3.speed, t3.climb, t3.track, t3.mode, t3.satellites,
        t4.humidity, t4.tempC, t4.tempF,
        t5.heading, t5.tempC, t5.tempF, t5.xAngle, t5.yAngle, t5.zAngle, t5.xAccel, t5.yAccel, t5.zAccel, t5.xMagn, t5.yMagn, t5.zMagn,
        t6.tempC, t6.tempF
        FROM hab_DEVICES t1
INNER JOIN hab_BMP085 t2 
ON (t1.id = t2.deviceId AND t1.id = 1 )
INNER JOIN hab_GPS t3
ON (t1.id = t3.deviceId AND t2.date = t3.date AND t2.time = t3.time AND t1.id = 1)
INNER JOIN hab_HIH6130 t4
ON (t1.id = t4.deviceId AND t2.date = t4.date AND t2.time = t4.time AND t1.id = 1)
INNER JOIN hab_MINIMU9V2 t5
ON (t1.id = t5.deviceId AND t2.date = t5.date AND t2.time = t5.time AND t1.id = 1)
INNER JOIN hab_RASPI t6
ON (t1.id = t6.deviceId AND t2.date = t6.date AND t2.time = t6.time AND t1.id = 1)  
WHERE t2.date = '2014-02-21'
AND t2.time >= '20:01:00'
AND t2.time <= '20:01:30'

Проверьте эту скрипту: http://sqlfiddle.com/#!2/639c05/24

Я принял за «основное время» время из таблицы 2, но вы можете использовать то, что имеет для вас больше смысла.

person Federico J.    schedule 16.03.2014
comment
Сейчас я использую INNER JOIN. Данный оператор предоставляет 63 набора данных. Добавление таблицы GPS дает 8064 набора данных. Добавление таблицы HIH6130 дает 1 032 192 набора данных. Помимо таблицы DEVICES, все таблицы имеют индекс по идентификатору, идентификатору устройства, дате и времени, где идентификатор — это первичный ключ. - person Daniel; 16.03.2014