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

Posted

技术标签:

【中文标题】如何使用 Diesel 计算数组列中不同元素的数量?【英文标题】:How do I count the number of distinct elements in an array column with Diesel? 【发布时间】:2019-01-21 22:46:00 【问题描述】:

我正在尝试使用 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。如果你想复制,克隆这个 repo 和cargo run。请注意,您必须在运行代码之前启动 Postgres 服务。

【问题讨论】:

【参考方案1】:

添加视图

从 Diesel 1.31 开始,最简单的做法是向数据库添加视图:

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

然后您可以告诉 Diesel 视图:

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 子句,可能还有其他限制。

【讨论】:

以上是关于如何使用 Diesel 计算数组列中不同元素的数量?的主要内容,如果未能解决你的问题,请参考以下文章

如何有效地计算另一列中每个元素的较大元素的数量?

如何有效地计算另一列中每个元素的较小元素的数量?

如何有效地计算列中每个元素的子元素数量?

计算数组中不同元素数量的最快方法

如何按对象计算熊猫组列中的不同值?

如何计算 NumPy bool 数组中真实元素的数量