MySQL 语法混乱 - 将简单数据合并在一起以实现优雅的单行插入
MySQL syntax confusion - Merging together simple data for a graceful single-row insertion
我正在构建一个 MySQL table 来为客户汇总一组特定信息。我已经使用简单的 INNER JOIN
命令对共享 keys/columns 的记录成功地组装和过滤了其中的大部分内容,但是数据的 pivoting/transposing,即使是固定大小,仍然导致我我的查询有些语法混乱。 table t_snapshots
的架构如下所示:
+-------------+---------------------+------+-----+---------------------+----------------+
| Field | Type | Null | Key | Default | Extra |
+-------------+---------------------+------+-----+---------------------+----------------+
| id | int(11) | NO | PRI | NULL | auto_increment |
| value_type | tinyint(1) unsigned | YES | | NULL | |
| ch1_id | varchar(20) | YES | | NULL | |
| ch1_val | float | NO | | 0 | |
| ch2_id | varchar(20) | YES | | NULL | |
| ch2_val | float | NO | | 0 | |
| ch3_id | varchar(20) | YES | | NULL | |
| ch3_val | float | NO | | 0 | |
| ch4_id | varchar(20) | YES | | NULL | |
| ch4_val | float | NO | | 0 | |
| timestamp | datetime | NO | MUL | current_timestamp() | |
+-------------+---------------------+------+-----+---------------------+----------------+
简单地说,我想 select 来自 t_other_data0.ch[n]
的最近更新的值发送到 t_snapshots.ch[n]_val
和 select 来自 [=19] 的最近更新的 id =] 将每个唯一 t_id_pool.channel_num
发送到 t_snapshots.ch[n]_id
。 t_id_pool.channel_num
与列 t_snapshots.ch[n]_val
:
的 n 值相关
--编辑--:理想情况下,来自源 table t_other_data0
的样本数据从 t_id_pool
中寻找 channel_num=1,2,3,4
的最新 unit_id
值并输出到 table t_snapshots
:
从 t_other_data0
收集最新的过程数据。在这种情况下,具有 id
5-8 的行被 selected 因为它们跨越所有不同的 value_type
和最新的 timestamp
.:
Table: t_other_data0
+----+------+------+------+------+------------+---------------------+
| id | ch1 | ch2 | ch3 | ch4 | value_type | timestamp |
+----+------+------+------+------+------------+---------------------+
| 1 | 1.65 | 3.25 | 1.98 | 2.17 | 1 | 2021-07-22 16:26:40 |
| 2 | 3.12 | 2.33 | 6.42 | 3.22 | 2 | 2021-07-22 16:26:40 |
| 3 | 2.22 | 2.24 | 3.34 | 1.17 | 3 | 2021-07-22 16:26:40 |
| 4 | 1.52 | 1.34 | 1.9 | 2.01 | 4 | 2021-07-22 16:26:40 |
| 5 | 3.2 | 3.21 | 5.42 | 2.13 | 1 | 2021-07-22 16:26:50 |
| 6 | 1.55 | 1.92 | 4.32 | 4.12 | 2 | 2021-07-22 16:26:50 |
| 7 | 2.31 | 1.93 | 2.36 | 3.4 | 3 | 2021-07-22 16:26:50 |
| 8 | 1.78 | 2.17 | 5.62 | 2.34 | 4 | 2021-07-22 16:26:50 |
+----+------+------+------+------+------------+---------------------+
因为这些永久频道改变了它们所绑定的临时设备,我们使用 t_id_pool
中最新的 unit_id
为每个 channel_num
确定当前的 unit_id
:
Table: t_id_pool
+----+---------------------+-------------+---------+
| id | timestamp | channel_num | unit_id |
+----+---------------------+-------------+---------+
| 1 | 2021-07-22 09:39:09 | 1 | S4251 |
| 2 | 2021-07-22 09:38:09 | 2 | S3552 |
| 3 | 2021-07-22 09:38:09 | 3 | S0001 |
| 4 | 2021-07-22 09:38:09 | 4 | S1001 |
| 5 | 2021-07-22 09:39:10 | 1 | P5251 |
| 6 | 2021-07-22 09:38:10 | 2 | P4552 |
| 7 | 2021-07-22 09:38:10 | 3 | P1001 |
| 8 | 2021-07-22 09:38:10 | 4 | P2001
+----+---------------------+-------------+---------+
输出到t_snapshots
:
Table: t_snapshots
+-----+---------------------+------------+--------+---------+--------+---------+--------+---------+--------+---------+
| id | timestamp | value_type | ch1_id | ch1_val | ch2_id | ch2_val | ch3_id | ch3_val | ch4_id | ch4_val |
+-----+---------------------+------------+--------+---------+--------+---------+--------+---------+--------+---------+
| 211 | 2021-07-14 16:26:50 | 1 | P5251 | 3.2 | P4552 | 3.21 | P1001 | 5.42 | P2001 | 2.13 |
| 212 | 2021-07-14 16:26:50 | 2 | P5251 | 1.55 | P4552 | 1.92 | P1001 | 4.32 | P2001 | 4.12 |
| 213 | 2021-07-14 16:26:50 | 3 | P5251 | 2.31 | P4552 | 1.93 | P1001 | 2.36 | P2001 | 3.4 |
+-----+---------------------+------------+--------+---------+--------+---------+--------+---------+--------+---------+
Tablet_other_data0
似乎是一个支点table。因此,我认为第一步是取消旋转它然后将其与 t_id_pool
table 连接以获得最新的 unit_id
,然后再次重新旋转它。也许像这样的查询可以工作:
SELECT 0 id, tod.timestamp, value_type,
MAX(case when channel_num=1 THEN unit_id else 0 END) AS ch1_id,
SUM(case when channel_num=1 then chan_val else 0 END) as ch1_val,
MAX(CASE WHEN channel_num=2 THEN unit_id ELSE 0 END) AS ch2_id,
SUM(CASE WHEN channel_num=2 THEN chan_val ELSE 0 END) AS ch2_val,
MAX(CASE WHEN channel_num=3 THEN unit_id ELSE 0 END) AS ch3_id,
SUM(CASE WHEN channel_num=3 THEN chan_val ELSE 0 END) AS ch3_val,
MAX(CASE WHEN channel_num=4 THEN unit_id ELSE 0 END) AS ch4_id,
SUM(CASE WHEN channel_num=4 THEN chan_val ELSE 0 END) AS ch4_val
FROM (SELECT value_type, ch1 AS chan_val, 1 AS chan_num, timestamp
FROM (SELECT *, Row_number() OVER (partition BY value_type ORDER BY id DESC) rn
FROM t_other_data0) AS A
WHERE rn = 1 UNION ALL
SELECT value_type, ch2, 2,
timestamp
FROM (SELECT *, Row_number() OVER (partition BY value_type ORDER BY id DESC) rn
FROM t_other_data0) AS A
WHERE rn = 1 UNION ALL
SELECT value_type, ch3, 3,
timestamp
FROM (SELECT *, Row_number() OVER (partition BY value_type ORDER BY id DESC) rn
FROM t_other_data0) AS A
WHERE rn = 1 UNION ALL
SELECT value_type, ch4, 4,
timestamp
FROM (SELECT *, Row_number() OVER (partition BY value_type ORDER BY id DESC) rn
FROM t_other_data0) AS A
WHERE rn = 1) AS tod
JOIN (SELECT id, timestamp, channel_num, unit_id,
Row_number() OVER (partition BY channel_num ORDER BY timestamp DESC) rn
FROM t_id_pool) AS tip
ON tod.chan_num = tip.channel_num AND tip.rn = 1
GROUP BY tod.timestamp, value_type;
这里使用的函数之一是 ROW_NUMBER()
,目的是在最新的 value_type
和 channel_number
时间戳上分配行号 1
。至于 table t_other_data0
,我使用的是 UNION ALL
,ch1, ch2, ch3 & ch4
列之后总共有 4 个查询。根据我选择的列,我为他们每个人分配了一个硬编码 chan_num
。
我不确定要填充什么的 id
列,但我认为由于查询的主要目的是 INSERT
到另一个 table,然后也许 id
列是自动递增的。
不幸的是,dbfiddle.uk 从昨天开始就不能使用了,所以这里的 fiddle 是 MySQL v8.0 而不是 MariaDB 10.3。 https://www.db-fiddle.com/f/xf1VmfYMbnGcabJS7dS6A1/1。 fiddle 中的结果将有一个额外的行 t_other_data.id=8
(@danblack 在评论中提到)并且不会包括 id=4
因为你的条件是 "Gather latest处理来自 t_other_table0" 的数据。但是从您的预期输出来看,您似乎没有包含 id=4
,所以您的描述中可能有一些打字错误。
我正在构建一个 MySQL table 来为客户汇总一组特定信息。我已经使用简单的 INNER JOIN
命令对共享 keys/columns 的记录成功地组装和过滤了其中的大部分内容,但是数据的 pivoting/transposing,即使是固定大小,仍然导致我我的查询有些语法混乱。 table t_snapshots
的架构如下所示:
+-------------+---------------------+------+-----+---------------------+----------------+
| Field | Type | Null | Key | Default | Extra |
+-------------+---------------------+------+-----+---------------------+----------------+
| id | int(11) | NO | PRI | NULL | auto_increment |
| value_type | tinyint(1) unsigned | YES | | NULL | |
| ch1_id | varchar(20) | YES | | NULL | |
| ch1_val | float | NO | | 0 | |
| ch2_id | varchar(20) | YES | | NULL | |
| ch2_val | float | NO | | 0 | |
| ch3_id | varchar(20) | YES | | NULL | |
| ch3_val | float | NO | | 0 | |
| ch4_id | varchar(20) | YES | | NULL | |
| ch4_val | float | NO | | 0 | |
| timestamp | datetime | NO | MUL | current_timestamp() | |
+-------------+---------------------+------+-----+---------------------+----------------+
简单地说,我想 select 来自 t_other_data0.ch[n]
的最近更新的值发送到 t_snapshots.ch[n]_val
和 select 来自 [=19] 的最近更新的 id =] 将每个唯一 t_id_pool.channel_num
发送到 t_snapshots.ch[n]_id
。 t_id_pool.channel_num
与列 t_snapshots.ch[n]_val
:
--编辑--:理想情况下,来自源 table t_other_data0
的样本数据从 t_id_pool
中寻找 channel_num=1,2,3,4
的最新 unit_id
值并输出到 table t_snapshots
:
从 t_other_data0
收集最新的过程数据。在这种情况下,具有 id
5-8 的行被 selected 因为它们跨越所有不同的 value_type
和最新的 timestamp
.:
Table: t_other_data0
+----+------+------+------+------+------------+---------------------+
| id | ch1 | ch2 | ch3 | ch4 | value_type | timestamp |
+----+------+------+------+------+------------+---------------------+
| 1 | 1.65 | 3.25 | 1.98 | 2.17 | 1 | 2021-07-22 16:26:40 |
| 2 | 3.12 | 2.33 | 6.42 | 3.22 | 2 | 2021-07-22 16:26:40 |
| 3 | 2.22 | 2.24 | 3.34 | 1.17 | 3 | 2021-07-22 16:26:40 |
| 4 | 1.52 | 1.34 | 1.9 | 2.01 | 4 | 2021-07-22 16:26:40 |
| 5 | 3.2 | 3.21 | 5.42 | 2.13 | 1 | 2021-07-22 16:26:50 |
| 6 | 1.55 | 1.92 | 4.32 | 4.12 | 2 | 2021-07-22 16:26:50 |
| 7 | 2.31 | 1.93 | 2.36 | 3.4 | 3 | 2021-07-22 16:26:50 |
| 8 | 1.78 | 2.17 | 5.62 | 2.34 | 4 | 2021-07-22 16:26:50 |
+----+------+------+------+------+------------+---------------------+
因为这些永久频道改变了它们所绑定的临时设备,我们使用 t_id_pool
中最新的 unit_id
为每个 channel_num
确定当前的 unit_id
:
Table: t_id_pool
+----+---------------------+-------------+---------+
| id | timestamp | channel_num | unit_id |
+----+---------------------+-------------+---------+
| 1 | 2021-07-22 09:39:09 | 1 | S4251 |
| 2 | 2021-07-22 09:38:09 | 2 | S3552 |
| 3 | 2021-07-22 09:38:09 | 3 | S0001 |
| 4 | 2021-07-22 09:38:09 | 4 | S1001 |
| 5 | 2021-07-22 09:39:10 | 1 | P5251 |
| 6 | 2021-07-22 09:38:10 | 2 | P4552 |
| 7 | 2021-07-22 09:38:10 | 3 | P1001 |
| 8 | 2021-07-22 09:38:10 | 4 | P2001
+----+---------------------+-------------+---------+
输出到t_snapshots
:
Table: t_snapshots
+-----+---------------------+------------+--------+---------+--------+---------+--------+---------+--------+---------+
| id | timestamp | value_type | ch1_id | ch1_val | ch2_id | ch2_val | ch3_id | ch3_val | ch4_id | ch4_val |
+-----+---------------------+------------+--------+---------+--------+---------+--------+---------+--------+---------+
| 211 | 2021-07-14 16:26:50 | 1 | P5251 | 3.2 | P4552 | 3.21 | P1001 | 5.42 | P2001 | 2.13 |
| 212 | 2021-07-14 16:26:50 | 2 | P5251 | 1.55 | P4552 | 1.92 | P1001 | 4.32 | P2001 | 4.12 |
| 213 | 2021-07-14 16:26:50 | 3 | P5251 | 2.31 | P4552 | 1.93 | P1001 | 2.36 | P2001 | 3.4 |
+-----+---------------------+------------+--------+---------+--------+---------+--------+---------+--------+---------+
Tablet_other_data0
似乎是一个支点table。因此,我认为第一步是取消旋转它然后将其与 t_id_pool
table 连接以获得最新的 unit_id
,然后再次重新旋转它。也许像这样的查询可以工作:
SELECT 0 id, tod.timestamp, value_type,
MAX(case when channel_num=1 THEN unit_id else 0 END) AS ch1_id,
SUM(case when channel_num=1 then chan_val else 0 END) as ch1_val,
MAX(CASE WHEN channel_num=2 THEN unit_id ELSE 0 END) AS ch2_id,
SUM(CASE WHEN channel_num=2 THEN chan_val ELSE 0 END) AS ch2_val,
MAX(CASE WHEN channel_num=3 THEN unit_id ELSE 0 END) AS ch3_id,
SUM(CASE WHEN channel_num=3 THEN chan_val ELSE 0 END) AS ch3_val,
MAX(CASE WHEN channel_num=4 THEN unit_id ELSE 0 END) AS ch4_id,
SUM(CASE WHEN channel_num=4 THEN chan_val ELSE 0 END) AS ch4_val
FROM (SELECT value_type, ch1 AS chan_val, 1 AS chan_num, timestamp
FROM (SELECT *, Row_number() OVER (partition BY value_type ORDER BY id DESC) rn
FROM t_other_data0) AS A
WHERE rn = 1 UNION ALL
SELECT value_type, ch2, 2,
timestamp
FROM (SELECT *, Row_number() OVER (partition BY value_type ORDER BY id DESC) rn
FROM t_other_data0) AS A
WHERE rn = 1 UNION ALL
SELECT value_type, ch3, 3,
timestamp
FROM (SELECT *, Row_number() OVER (partition BY value_type ORDER BY id DESC) rn
FROM t_other_data0) AS A
WHERE rn = 1 UNION ALL
SELECT value_type, ch4, 4,
timestamp
FROM (SELECT *, Row_number() OVER (partition BY value_type ORDER BY id DESC) rn
FROM t_other_data0) AS A
WHERE rn = 1) AS tod
JOIN (SELECT id, timestamp, channel_num, unit_id,
Row_number() OVER (partition BY channel_num ORDER BY timestamp DESC) rn
FROM t_id_pool) AS tip
ON tod.chan_num = tip.channel_num AND tip.rn = 1
GROUP BY tod.timestamp, value_type;
这里使用的函数之一是 ROW_NUMBER()
,目的是在最新的 value_type
和 channel_number
时间戳上分配行号 1
。至于 table t_other_data0
,我使用的是 UNION ALL
,ch1, ch2, ch3 & ch4
列之后总共有 4 个查询。根据我选择的列,我为他们每个人分配了一个硬编码 chan_num
。
我不确定要填充什么的 id
列,但我认为由于查询的主要目的是 INSERT
到另一个 table,然后也许 id
列是自动递增的。
不幸的是,dbfiddle.uk 从昨天开始就不能使用了,所以这里的 fiddle 是 MySQL v8.0 而不是 MariaDB 10.3。 https://www.db-fiddle.com/f/xf1VmfYMbnGcabJS7dS6A1/1。 fiddle 中的结果将有一个额外的行 t_other_data.id=8
(@danblack 在评论中提到)并且不会包括 id=4
因为你的条件是 "Gather latest处理来自 t_other_table0" 的数据。但是从您的预期输出来看,您似乎没有包含 id=4
,所以您的描述中可能有一些打字错误。