SQLite 长到宽格式?

发布于 2024-08-25 07:06:25 字数 216 浏览 3 评论 0 原文

我想知道是否有一种规范的方法可以在 SQLite 中将数据从长格式转换为宽格式(该操作通常在关系数据库领域吗?)。我尝试按照 MySQL 的 这个示例 进行操作,但我猜是 SQLite没有相同的 IF 结构...谢谢!

I wonder if there is a canonical way to convert data from long to wide format in SQLite (is that operation usually in the domain of relational databases?). I tried to follow this example for MySQL but I guess SQLite does not have the same IF construct... Thanks!

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

巴黎盛开的樱花 2024-09-01 07:06:25

IF 是一个非标准 MySQL 扩展。最好始终使用 CASE,它是标准 SQL,适用于所有兼容的数据库,包括 SQLite 和 MySQL(以及 MSSQL、Oracle、Postgres、Access、Sybase...等等)。

下面是如何使用 CASE 执行相同查询的示例:

SELECT      Country,
            MAX(CASE WHEN Key = 'President' THEN Value ELSE NULL END) President,
            MAX(CASE WHEN Key = 'Currency' THEN Value ELSE NULL END) Currency
FROM        Long
GROUP BY    Country
ORDER BY    Country;

这是使用联接表示相同查询的另一种方法。我认为这可能更有效,但它假设每个组中的每个键值只有一条记录(CASE版本也是如此,但如果不是这样,不会导致额外的行,只是更少- 超出预期的结果)。

SELECT
    D.Country,
    P.Value President,
    C.Value Currency
FROM
    (
        SELECT DISTINCT Country
        FROM    Long
    ) D
            INNER JOIN
    (   SELECT  Country, Value
        FROM    Long
        WHERE   Key = 'President'
    ) P
            ON
        D.Country = P.Country
            INNER JOIN
    (   SELECT  Country, Value
        FROM    Long
        WHERE   Key = 'Currency'
    ) C
            ON
        D.Country = C.Country
ORDER BY
    D.Country;

作为记录,以下是我使用的 DDL 和测试数据:

CREATE TABLE Long (ID INTEGER PRIMARY KEY AUTOINCREMENT, Country TEXT, Key TEXT, Value TEXT);

INSERT INTO Long VALUES (NULL, 'USA', 'President', 'Obama');
INSERT INTO Long VALUES (NULL, 'USA', 'Currency', 'Dollar');
INSERT INTO Long VALUES (NULL, 'China', 'President', 'Hu');
INSERT INTO Long VALUES (NULL, 'China', 'Currency', 'Yuan');

IF is a non-standard MySQL extension. It's better to always use CASE which is standard SQL and works in all compliant databases, including SQLite and MySQL (and MSSQL, Oracle, Postgres, Access, Sybase... and on and on).

Here's an example of how to do the same query with CASE:

SELECT      Country,
            MAX(CASE WHEN Key = 'President' THEN Value ELSE NULL END) President,
            MAX(CASE WHEN Key = 'Currency' THEN Value ELSE NULL END) Currency
FROM        Long
GROUP BY    Country
ORDER BY    Country;

Here's another way to represent the same query using joins. I think this is probably more efficient, but it assumes there's only one record for each key value within each group (the CASE version does too, but will not result in extra rows if that's not true, just less-than-predictable results).

SELECT
    D.Country,
    P.Value President,
    C.Value Currency
FROM
    (
        SELECT DISTINCT Country
        FROM    Long
    ) D
            INNER JOIN
    (   SELECT  Country, Value
        FROM    Long
        WHERE   Key = 'President'
    ) P
            ON
        D.Country = P.Country
            INNER JOIN
    (   SELECT  Country, Value
        FROM    Long
        WHERE   Key = 'Currency'
    ) C
            ON
        D.Country = C.Country
ORDER BY
    D.Country;

And for the record, here's the DDL and test data I was using:

CREATE TABLE Long (ID INTEGER PRIMARY KEY AUTOINCREMENT, Country TEXT, Key TEXT, Value TEXT);

INSERT INTO Long VALUES (NULL, 'USA', 'President', 'Obama');
INSERT INTO Long VALUES (NULL, 'USA', 'Currency', 'Dollar');
INSERT INTO Long VALUES (NULL, 'China', 'President', 'Hu');
INSERT INTO Long VALUES (NULL, 'China', 'Currency', 'Yuan');
天荒地未老 2024-09-01 07:06:25

作为上面优秀答案的更新(作为通用解决方案),并引用 介绍了 3.32.0版本中的IIF()函数:

iif(X,Y,Z)

如果 X 为 true,则 iif(X,Y,Z) 函数返回值 Y,否则返回 Z。 iif(X,Y,Z) 函数在逻辑上等同于 CASE 表达式 CASE WHEN X THEN Y ELSE Z END,并生成相同的字节码。

使用接受的答案的 DDL,以下查询:

SELECT Country,
    MAX( IIF(key='President', Value, NULL)) President,
    MAX( IIF(key='Currency', Value, NULL)) Currency
FROM Long
GROUP BY Country;

... 应将 格式重塑:

┌────┬─────────┬───────────┬────────┐
│ ID │ Country │    Key    │ Value  │
├────┼─────────┼───────────┼────────┤
│ 1  │ USA     │ President │ Obama  │
│ 2  │ USA     │ Currency  │ Dollar │
│ 3  │ China   │ President │ Hu     │
│ 4  │ China   │ Currency  │ Yuan   │
└────┴─────────┴───────────┴────────┘

... 为 格式:

┌─────────┬───────────┬──────────┐
│ Country │ President │ Currency │
├─────────┼───────────┼──────────┤
│ China   │ Hu        │ Yuan     │
│ USA     │ Obama     │ Dollar   │
└─────────┴───────────┴──────────┘

这里我们转置 行和列。

As an update to the excellent answer above (being a generalizable solution), and referencing the example cited in the OP, SQLite introduced the IIF() function in version 3.32.0:

iif(X,Y,Z)

The iif(X,Y,Z) function returns the value Y if X is true, and Z otherwise. The iif(X,Y,Z) function is logically equivalent to and generates the same bytecode as the CASE expression CASE WHEN X THEN Y ELSE Z END.

Using the accepted answer's DDL, the following query:

SELECT Country,
    MAX( IIF(key='President', Value, NULL)) President,
    MAX( IIF(key='Currency', Value, NULL)) Currency
FROM Long
GROUP BY Country;

... should reshape the long format:

┌────┬─────────┬───────────┬────────┐
│ ID │ Country │    Key    │ Value  │
├────┼─────────┼───────────┼────────┤
│ 1  │ USA     │ President │ Obama  │
│ 2  │ USA     │ Currency  │ Dollar │
│ 3  │ China   │ President │ Hu     │
│ 4  │ China   │ Currency  │ Yuan   │
└────┴─────────┴───────────┴────────┘

... to the wide format:

┌─────────┬───────────┬──────────┐
│ Country │ President │ Currency │
├─────────┼───────────┼──────────┤
│ China   │ Hu        │ Yuan     │
│ USA     │ Obama     │ Dollar   │
└─────────┴───────────┴──────────┘

Here we have transposed rows and columns.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文