如何使用 Diesel 计算数组列中不同元素的数量?
How do I count the number of distinct elements in an array column with Diesel?
我正在尝试实现 count_distinct_labels
函数以使用 Diesel 和 PostgreSQL.
计算数组列中的不同元素
例如,我有一个这样的table:
------------------
| labels |
------------------
| ['foo', 'bar'] |
------------------
| ['bar', 'baz'] |
------------------
在这种情况下,count_distinct_labels()
应该是 3
,因为有 3 个唯一标签 ('foo', 'bar', 'baz'
)。
我发现下面的 SQL returns 是我想要的结果,但我不知道如何将其转换成 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 服务。
添加视图
从 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
你总是可以退回到直接执行"big hammer"的"big hammer":
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
子句,也许还有其他限制。
我正在尝试实现 count_distinct_labels
函数以使用 Diesel 和 PostgreSQL.
例如,我有一个这样的table:
------------------
| labels |
------------------
| ['foo', 'bar'] |
------------------
| ['bar', 'baz'] |
------------------
在这种情况下,count_distinct_labels()
应该是 3
,因为有 3 个唯一标签 ('foo', 'bar', 'baz'
)。
我发现下面的 SQL returns 是我想要的结果,但我不知道如何将其转换成 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 服务。
添加视图
从 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
你总是可以退回到直接执行"big hammer"的"big hammer":
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
子句,也许还有其他限制。