#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 был принят.