在不使用扩展的情况下动态转置 SQLite 中的行
Posted
技术标签:
【中文标题】在不使用扩展的情况下动态转置 SQLite 中的行【英文标题】:Dynamically transpose rows in SQLite without using extensions 【发布时间】:2021-12-29 15:28:09 【问题描述】:我在 SQLite 中创建查询时遇到问题。
我有两个通过 ID 关联的 SQL 表,我想在加入它们后转置其中的一些行。
由于我无法共享来自真实数据库的信息,因此我创建了一个玩具数据库来更好地说明我想要实现的目标。在这里,我有一个 MAINTABLE
,包含它自己的 id 和更多东西,还有一个 SECONDARYTABLE
,包含它自己的 id、对 MAINTABLE
的引用和键/值对。
MAINTABLE
idMainTable MoreStuff
1 asdf
2 fdsa
3 hjkl
4 lkhj
SECONDARY TABLE
idSecondaryTable idMainTable key value
1 1 Key1 a
2 1 Key5 s
3 1 Key7 d
4 1 Key8 f
5 2 Key1 g
6 2 Key4 h
7 2 Key25 j
8 3 Key2 l
9 3 Key6 z
10 4 Key7 y
我想在这里做的是一个能够连接这两个表的查询,并将键和值行转换为这样的列,因此键是结果表中的列:
EXPECTED TABLE
idMainTable MoreStuff Key1 Key2 Key4 Key5 Key6 Key7 Key8 Key25
1 asdf a null null s null d f null
2 fdsa g null h null null null null j
3 hjkl null l null null z null null null
4 lkhj null null null null null y null null
我不介意键是否已排序,或者空单元格是否显示为 null 或空单元格。
我从this link 知道,当不同键的名称已知时,可以在此处应用条件聚合。但是,我不知道键的数量或键的可能名称,这就是我正在寻找动态解决方案的原因。在此链接中,还提出了一个名为pivot_vtab 的 SQLite 扩展,但扩展的使用在我的项目中是一个限制,我不能使用它。
在 mysql 中,可以选择使用 GROUP_CONCAT。我在 MySQL 中尝试过,它可以工作。但是,我一直在 SQLite 中尝试类似的方法,但我无法做到这一点。
这是在 MySQL 中运行的查询,给出了想要的结果:
SET @sql = NULL;
SELECT
GROUP_CONCAT(DISTINCT
CONCAT(
'MAX(IF(keyColumn = ''',
keyColumn,
''', value, NULL)) AS ',
keyColumn
)
) INTO @sql
FROM (MainTable INNER JOIN SecondaryTable ON MainTable.idMainTable =
SecondaryTable.idMainTable);
SET @sql = CONCAT("SELECT SecondaryTable.idMainTable, ", @sql,
" FROM (MainTable INNER JOIN SecondaryTable ON MainTable.idMainTable =
SecondaryTable.idMainTable)
GROUP BY SecondaryTable.idMainTable");
PREPARE stmt FROM @sql;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;
这是在 SQLite 中创建玩具数据库的代码:
PRAGMA foreign_keys = ON;
BEGIN TRANSACTION;
CREATE TABLE IF NOT EXISTS `MainTable` (
`idMainTable` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL,
`MoreStuff` VARCHAR(45) NOT NULL,
UNIQUE (`idMainTable` ASC));
CREATE TABLE IF NOT EXISTS `SecondaryTable` (
`idSecondaryTable` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL,
`idMainTable` INTEGER NOT NULL,
`keyColumn` VARCHAR(45) NOT NULL,
`value` VARCHAR(45) NOT NULL,
UNIQUE (`idSecondaryTable` ASC),
CONSTRAINT `fk_SecondaryTable_1`
FOREIGN KEY (`idMainTable`)
REFERENCES `MainTable` (`idMainTable`)
ON DELETE NO ACTION
ON UPDATE NO ACTION);
COMMIT;
BEGIN TRANSACTION;
INSERT INTO `MainTable` (`MoreStuff`) VALUES ('asdf');
INSERT INTO `MainTable` (`MoreStuff`) VALUES ('fdsa');
INSERT INTO `MainTable` (`MoreStuff`) VALUES ('hjkl');
INSERT INTO `MainTable` (`MoreStuff`) VALUES ('lkhj');
INSERT INTO `SecondaryTable` (`idMainTable`, `keyColumn`, `value`) VALUES (1, 'Key1', 'a');
INSERT INTO `SecondaryTable` (`idMainTable`, `keyColumn`, `value`) VALUES (1, 'Key5', 's');
INSERT INTO `SecondaryTable` (`idMainTable`, `keyColumn`, `value`) VALUES (1, 'Key7', 'd');
INSERT INTO `SecondaryTable` (`idMainTable`, `keyColumn`, `value`) VALUES (1, 'Key8', 'f');
INSERT INTO `SecondaryTable` (`idMainTable`, `keyColumn`, `value`) VALUES (2, 'Key1', 'g');
INSERT INTO `SecondaryTable` (`idMainTable`, `keyColumn`, `value`) VALUES (2, 'Key4', 'h');
INSERT INTO `SecondaryTable` (`idMainTable`, `keyColumn`, `value`) VALUES (2, 'Key25', 'j');
INSERT INTO `SecondaryTable` (`idMainTable`, `keyColumn`, `value`) VALUES (3, 'Key2', 'l');
INSERT INTO `SecondaryTable` (`idMainTable`, `keyColumn`, `value`) VALUES (3, 'Key6', 'z');
INSERT INTO `SecondaryTable` (`idMainTable`, `keyColumn`, `value`) VALUES (4, 'Key7', 'y');
COMMIT;
出于测试目的,我使用以下online SQLite IDE 来生成所需的查询。
有没有一种方法可以使用 SQLite 实现我所描述的,无需扩展?
【问题讨论】:
SQLite 不支持动态 sql。 如果您事先知道要转置的列,您可以轻松实现它,但如果您想要动态地实现它,不幸的是不能仅使用 SQLite。您将需要使用您使用的任何编程语言加上 sqlite 采取两步。 我明白了。然后我将使用我正在使用的编程语言来生成新表。谢谢你们俩! 【参考方案1】:看起来没有办法使用纯 SQLite 来实现这一点,就像 cmets 中显示的那样。
正如 cmets 中所建议的,可以使用另一种编程语言(例如 C++)构建动态查询。
以下链接也证实了这一点:
StackExchange: Is it possible to create Dynamic SQL statements purely in SQLite?
StackExchange: How to pivot data in SQLite
***: SQLITE transpose large number of rows into columns
如果以后这种情况发生变化,我会接受其他答案,或者如果我自己发现更新这个。
【讨论】:
以上是关于在不使用扩展的情况下动态转置 SQLite 中的行的主要内容,如果未能解决你的问题,请参考以下文章
如何在不使用count(*)的情况下在greenplum中查找表中的行数
是否可以在不运行 DbVisualizer + SQLite 中的原始 sql 的情况下更改列
在不安装sqlite3的时候使用sqlite3数据库以及问题/usr/bin/ld: skipping incompatible.....的解决