2015-08-12 3 views
-1

дана таблица с именем RECORD в MySQL со следующей структурой:MySQL присоединиться к тем же таблицам

rid(pk & AI) patientid(fk) recordTYPE(varchar) recordValue(varchar) recordTimestamp(timestamp) 
    1    1    temperature(℃)   37.2    2015-08-11 18:10:04 
    2    1    weight(kg)    65.0    2015-08-11 18:20:08      
    3    1    heartbeat(bpm)   66    2015-08-11 18:30:08 
    4    1    temperature(℃)   36.8    2015-08-11 18:32:08 

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

rid  patientid   recordTYPE    value    recordtimestamp 
    1    1    temperature(℃)   37.2    2015-08-11 18:10:04 
    4    1    temperature(℃)   36.8    2015-08-11 18:32:08 

В этом случае мы должны выбрать самую последнюю запись. то есть запись со сбросом = 4 и значением = 36,8.

Теперь дана дата ввода, например. «2015-8-11», я хочу, чтобы сделать запрос, чтобы получить что-то вроде:

date  patientid temperature(℃) weight(kg) heartbeat(bpm) 
2015-08-11  1   36.8    65.0   66 
2015-08-11  2   36.5    80.3   70 
2015-08-11  3   35.5    90.5   80 
    .......................................................... 
    .......................................................... 
2015-08-11  4   35.5    null   null 
           Fig. 2 

Кроме того, вы можете увидеть, что для определенной даты, не может быть никаких записей некоторых типов. В этом случае значение в этом столбце равно null.

Я попробовал следующий запрос:

SELECT max(recordTimestamp), patientid, recordTYPE, recordValue 
    FROM RECORD 
    WHERE date(recordTimestamp) = '2015-08-11' 
    GROUP BY patientid, recordTYPE 

В результате получается нечто вроде:

date  patientid  recordTYPE  recordValue  
2015-08-11  1  temperature(℃) 36.8    
2015-08-11  1   weight(kg)  65.0    
2015-08-11  1  heartbeat(bpm) 66 
2015-08-11  2  temperature(℃) 36.5    
2015-08-11  2   weight(kg)  80.3    
2015-08-11  2  heartbeat(bpm) 70 
2015-08-11  4  temperature(℃) 35.5    
           Fig. 4 

Вопросов:

  1. Учитывая эту таблицу RECORD, что правильная инструкция mysql (в терминах производительности, такой как скорость поиска), чтобы получить желаемый набор результатов (т. Рис.2)?

  2. Будет ли лучше (с точки зрения облегчения запросов и масштабируемости, таких как добавление новых типов записей), если будет изменен дизайн db? , например. Создайте одну таблицу для каждого типа записей вместо того, чтобы помещать все типы записей в одну таблицу.

Любое предложение ценится как я дб новичок ...... Спасибо.

+0

Структура в порядке; это действительно зависит от того, как будет использоваться таблица (как будут получать данные, какие запросы будут выполняться против нее, будут ли они связаны с данными в других таблицах и т. д.); поэтому не может точно сказать, что это лучшее решение, но никаких тревожных звонков. 'recordTYPE' лучше всего заменить внешним ключом, ссылающимся на другую таблицу; таким образом вы уменьшаете размер каждой строки и улучшаете ремонтопригодность. – JohnLBevan

ответ

0

Вы можете попробовать это: -

SELECT MAX(rid), patientid, recordTYPE, MAX(recordValue), recordTimestamp 
FROM YOUR_TABLE 
WHERE recordTimestamp = '2015/08/11' 
GROUP BY patientid, recordTYPE, recordTimestamp; 
+0

Спасибо, НО этот запрос не дает ожидаемого –

+0

Теперь попробуйте мое редактирование. –

0

Вот один из способов сделать это. SQL Fiddle Demo

К сожалению, MySQL не поддерживает синтаксис row_number() over (partition by ...), который бы упростил это. Вместо этого я сделал чрезмерное использование трюк обсуждается здесь: https://stackoverflow.com/a/3470355/361842

select `date` 
, `patientId` 
, max(case when `tRank`=1 then `temperature(℃)` else null end) `temperature(℃)` 
, max(case when `wRank`=1 then `weight(kg)` else null end) `weight(kg)` 
, max(case when `hRank`=1 then `heartbeat(bpm)` else null end) `heartbeat(bpm)` 
from 
(
    select case when @p = `patientId` and @d = cast(`recordTimestamp` as date) then @x := 1 else @x := 0 end 
    , case when @x = 0 then @t := 0 end 
    , case when @x = 0 then @w := 0 end 
    , case when @x = 0 then @h := 0 end 
    , case `recordType` when 'temperature(℃)' then case @x when 1 then @t := @t + 1 else @t := 1 end else null end as `tRank`  
    , case `recordType` when 'weight(kg)'  then case @x when 1 then @w := @w + 1 else @t := 1 end else null end as `wRank`  
    , case `recordType` when 'heartbeat(bpm)' then case @x when 1 then @h := @h + 1 else @t := 1 end else null end as `hRank` 
    , case `recordType` when 'temperature(℃)' then `recordValue` else null end as `temperature(℃)`  
    , case `recordType` when 'weight(kg)'  then `recordValue` else null end as `weight(kg)`  
    , case `recordType` when 'heartbeat(bpm)' then `recordValue` else null end as `heartbeat(bpm)` 
    , @d := cast(`recordTimestamp` as date) as `date` 
    , @p := `patientId` as `patientId` 
    from `Record` 
    cross join 
    (
     SELECT @t := 0 
     , @w := 0 
     , @h := 0 
     , @p := 0 
     , @x := 0 
     , @d := cast(null as date) 
    ) x 
    order by `patientId`, `recordTimestamp` desc 
) y 
group by `date`, `patientId` 
order by `date`, `patientId` 

Разбивка

Это говорит о том, что, если это последняя температура дня для partientId в текущей группировки в/date комбо, а затем вернуть его; в противном случае возвращает null. Затем он принимает максимальное значение соответствия (которое дает все значения, кроме 1, равно нулю, дает нам тот, который мы после него).

, max(case when `tRank`=1 then `temperature(℃)` else null end) 

Как tRank = 1 означает последнюю температуру дня для patientId/дата комбо объясняется позже.

В этой строке указано, что если эта запись имеет тот же самый пациент и дату, что и предыдущая запись, тогда установите x в 1; если это новый комбо установить его в 0.

select case when @p = `patientId` and @d = cast(`recordTimestamp` as date) then @x := 1 else @x := 0 end 

Следующие строки говорят, что если у нас есть новый patiendIt/дата комбо, сброс маркеров t, w и h сказать «следующее значение, которое вы получите, будет тот, который мы после ".

, case when @x = 0 then @t := 0 end 

Следующие строки разбивают данные на recordType; возвращая значение null, если эта запись не является типом записи, или возвращает число, в котором указано, сколько из этого типа записей мы теперь видели для комбинации yearId/date.

, case `recordType` when 'temperature(℃)' then case @x when 1 then @t := @t + 1 else @t := 1 end else null end as `tRank`  

Это похоже на вышесказанное; кроме вместо того, чтобы возвращать комбинированный счетчик, он возвращает значение текущей записи (или null, если это другой тип записи).

, case `recordType` when 'temperature(℃)' then `recordValue` else null end as `temperature(℃)`  

Затем мы записываем значение даты и patientId текущей записи, так что мы можем сравнить их со следующей записью на следующей итерации.

, @d := cast(`recordTimestamp` as date) as `date` 
, @p := `patientId` as `patientId` 

cross join и после подзапрос используется только для инициализации наших переменных.

(первый) order by используется для проверки того, что сравнение текущей и предыдущей записей достаточно, чтобы определить, если мы смотрим на другую комбинацию (т. Е. Если все комбо сгруппированы, любое изменение легко обнаружить, если комбо сохранить чередуясь, нам нужно будет отслеживать каждую комбинацию, которую мы видели раньше). recordTimestamp сортируется по убыванию, так что первая запись, которую мы видим в новом комбо, будет последней записью в тот день; тот, за которым мы следим.

group by используется, чтобы гарантировать, что мы получим 1 результат на комбо; и последние order by, чтобы сделать наш заказ заказанным.

Смежные вопросы