sql - 如何使用 Diesel 计算数组列中不同元素的数量?

标签 sql postgresql rust rust-diesel

我正在尝试使用 Diesel 和 PostgreSQL 实现 count_distinct_labels 函数来计算数组列中的不同元素。

例如,我有一个这样的表:

------------------
|     labels     |
------------------
| ['foo', 'bar'] |
------------------
| ['bar', 'baz'] |
------------------

在本例中,count_distinct_labels() 应为 3,因为有 3 个唯一标签('foo'、'bar'、'baz')。

我发现以下 SQL 返回了所需的结果,但我不知道如何将其转换为 Diesel 表达式。

SELECT COUNT(*) FROM (SELECT DISTINCT unnest(labels) FROM t) AS label;

这是我的源代码:

#[macro_use]
extern crate diesel;
extern crate dotenv;

use diesel::pg::PgConnection;
use diesel::prelude::*;
use dotenv::dotenv;
use std::env;

mod schema {
    table! {
        t (id) {
            id -> Int4,
            labels -> Array<Text>,
        }
    }

    #[derive(Insertable)]
    #[table_name = "t"]
    pub struct NewRow<'a> {
        pub labels: &'a [String],
    }
}

fn count_distinct_labels(conn: &PgConnection) -> i64 {
    // SELECT COUNT(*) FROM (SELECT DISTINCT unnest(labels) FROM t) AS label
    unimplemented!()
}

fn main() {
    dotenv().ok();

    let database_url = env::var("DATABASE_URL").expect("DATABASE_URL must be set");
    let conn = PgConnection::establish(&database_url)
        .expect(&format!("Error connecting to {}", database_url));

    diesel::insert_into(schema::t::dsl::t)
        .values(&vec![
            schema::NewRow {
                labels: &["foo".to_string(), "bar".to_string()],
            },
            schema::NewRow {
                labels: &["bar".to_string(), "baz".to_string()],
            },
        ]).execute(&conn)
        .unwrap();

    // how to implement?
    assert_eq!(count_distinct_labels(&conn), 3);
}

和 Cargo.toml:

[package]
name = "how-to-count-distinct"
version = "0.1.0"
authors = ["name"]

[dependencies]
diesel = { version = "1.0", features = ["postgres"] }
dotenv = "0.13"

我还创建了a repo containing the full example 。如果您想重现,请克隆此存储库并cargo run。请注意,在运行代码之前,您必须启动 Postgres 服务。

最佳答案

添加 View

从 Diesel 1.31 开始,最简单的事情就是向数据库添加 View :

CREATE VIEW unique_labels AS (SELECT DISTINCT unnest(labels) FROM t);

然后您可以告诉 Diesel 有关 View 的信息:

table! {
    unique_labels (unnest) {
        unnest -> Text,
    }
}

并直接查询:

fn count_distinct_labels(conn: &PgConnection) -> i64 {
    use schema::unique_labels::dsl::*;
    use diesel::dsl;

    unique_labels.select(dsl::count_star()).first(conn).unwrap()
}

使用sql_query

你总是可以退回到直接执行SQL的“大锤子”:

fn count_distinct_labels(conn: &PgConnection) -> i64 {
    use diesel::sql_types::BigInt;

    #[derive(QueryableByName)]
    struct Count {
        #[sql_type = "BigInt"]
        count: i64,
    }

    diesel::sql_query(r#"SELECT COUNT(*) FROM (SELECT DISTINCT unnest(labels) FROM t) AS label"#)
        .load::<Count>(conn)
        .expect("Query failed")
        .pop()
        .expect("No rows")
        .count
}

1 Diesel 1.3 无法手动传递您自己的 FROM 子句,也许还有其他限制。

关于sql - 如何使用 Diesel 计算数组列中不同元素的数量?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/51852226/

相关文章:

Java SQL COUNT 值

sql - 设计条件关系

django - Docker-compose 添加 Postgres 密码

rust - 为什么使用 println 宏时可以格式化变量,但不能格式化数组元素?

java - com.microsoft.sqlserver.jdbc.SQLServerException : Conversion failed when converting the nvarchar value '123.0' to data type int

performance - 应该将 search_data tsvector 存储在同一张表还是外部表中?

javascript - Sequelize 错误 : Relation does not exist

Rust:对可能拥有的引用中的借用进行生命周期检查

rust - 如何检索在 Rust 中使用 docopt 时使用的子命令?

mysql - ORDER BY 来自不同表的具有相同选项 ID 的行数