SQL-запрос для получения разных рядов данных, содержащихся в одной таблице

#sql #sqlite

#sql #sqlite

Вопрос:

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

 row | timestamp | seriesId | int32 | int64 | double
---------------------------------------------------
  0 |         0 |        0 |     2 |       |
  1 |         1 |        0 |     4 |       |
  2 |         1 |        1 |   435 |       |
  3 |         1 |        2 |       |  2345 |
  4 |         1 |        3 |       |       |    0.5
  5 |         2 |        0 |     5 |       |
  6 |         2 |        1 |   453 |       |
  7 |         2 |        2 |       |  2401 |
  ....
  

Я хотел бы получить результирующий набор, который выглядит следующим образом (чтобы я мог легко его отобразить):

 row | timestamp | series0 | series1 | series 2 | ...
----------------------------------------------------
  0 |         0 |       2 |         |          |
  1 |         1 |       4 |     435 |     2345 |
  2 |         2 |       5 |     453 |     2401 |
...
  

К сожалению, мои навыки SQL не совсем такие, какими они должны быть, поэтому моя первая попытка добиться этого кажется немного неловкой:

 SELECT tbl0.timestamp, tbl0.int32 as series0,
       tbl1.int32 as series1
FROM
      (SELECT * FROM StreamData WHERE seriesId=0) as tbl0
    INNER JOIN
      (SELECT * FROM StreamData WHERE seriesId=1) as tbl1
    ON tbl0.timestamp = tbl1.timestamp
ORDER BY tbl0.timestamp;
  

На самом деле это не кажется правильным способом достижения этой цели, особенно когда количество разных рядов увеличивается. Я могу изменить способ хранения данных в таблице (это в базе данных SQLite, если это имеет значение), если это упростит задачу, но поскольку количество разных рядов может время от времени отличаться, я бы предпочел, чтобы они все были в одной таблице.

Есть ли лучший способ написать приведенный выше запрос?

Ответ №1:

Кажется, вам нужно использовать «group by»:

 SELECT row, timestamp, count(seriedIS) AS series0, sum(int32) AS series1, sum(int64) AS series2
FROM StreamData
WHERE (streamId=0) OR (streamId=1)
GROUP BY (timestamp)
ORDER BY timestamp;
  

Просто попробуйте!

Комментарии:

1. Это не приводит к выводу, который требуется оператору.

2. Действительно ли SQLite позволяет вам выбирать row без группировки по нему?

3. Я группирую по метке времени .. : S

4. Да, я знаю, что это так. Но вы также выбираете row поле, не группируя по нему. Вот почему я спрашиваю, действительно ли SQLite позволяет это.

5. Ах, хорошо, теперь я понимаю! Да, sqlite позволяет это, но записывает случайное значение строки! На самом деле, не важно выбирать столбец «строка»!

Ответ №2:

Это будет работать, только если вы знаете, сколько серий вы там сохранили. Таким образом, сжатие INT32, INT64 и DOUBLE down будет работать нормально. Но поскольку у вас может быть любое количество идентификаторов SeriesID, здесь возникает проблема.

Вот как сжать столбцы с нулевым значением (игнорируя существование SeriesID).

 SELECT
  timestamp,
  MAX(int32)             AS series0,
  MAX(int64)             AS series1,
  MAX(double)            AS series2
FROM
  StreamData
GROUP BY
  timestamp
  

Если вы знаете точное количество рядов, вы можете изменить его следующим образом…

 SELECT
  timestamp,
  MAX(CASE WHEN seriesID = 0 THEN int32  ELSE NULL END)             AS series0,
  MAX(CASE WHEN seriesID = 1 THEN int64  ELSE NULL END)             AS series1,
  MAX(CASE WHEN seriesID = 2 THEN double ELSE NULL END)             AS series2,
  MAX(CASE WHEN seriesID = 3 THEN int32  ELSE NULL END)             AS series3,
  MAX(CASE WHEN seriesID = 4 THEN int64  ELSE NULL END)             AS series4,
  MAX(CASE WHEN seriesID = 5 THEN double ELSE NULL END)             AS series5
FROM
  StreamData
GROUP BY
  timestamp
  

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

Комментарии:

1. Я решил принять этот ответ, хотя все ответы, похоже, использовали в основном один и тот же подход к решению этой проблемы. Это был просто код запроса, который соответствовал наилучшим образом.

Ответ №3:

Если у вас есть потенциально переменное число seriesId , вам нужно будет динамически собирать SQL-запрос. Это должно выглядеть так:

 select 
    TimeStamp,
    Max(case seriesId when 0 then coalesce(int32, int64) else null end) series0,
    Max(case seriesId when 1 then coalesce(int32, int64) else null end) series1,
    Max(case seriesId when 2 then coalesce(int32, int64) else null end) series2,
    Max(case seriesId when 3 then coalesce(int32, int64) else null end) series3,
    Max(case seriesId when 4 then coalesce(int32, int64) else null end) series4,
    Max(case seriesId when 5 then coalesce(int32, int64) else null end) series5,
    Max(case seriesId when 6 then coalesce(int32, int64) else null end) series6
from StreamData 
group by TimeStamp
order by TimeStamp
  

Также из вашего примера данных я понял, что вы получаете либо int32 или int64 , в зависимости от int32 nullity, таким образом, coalesce .

Комментарии:

1. Как насчет двойного столбца dolumn? Возможно, если вы хотите использовать подход coalesce, вам нужно что-то вроде… COALESCE([double], CAST([int64] AS DOUBLE), CAST([int32] AS DOUBLE))

2. 1 за хороший ответ, мне, вероятно, не нужна функция coalesce() , поэтому ответ Dems был принят.