Calculate table column using over table on server side

一个人想着一个人 提交于 2019-12-08 05:44:22

问题


Suppose, there are two tables in db:

Table registries:

       Column       |            Type             |                           
--------------------+-----------------------------+---------
 registry_id        | integer                     | not null 
 name               | character varying           | not null
 ...
 uploaded_at        | timestamp without time zone | not null

Table rows:

    Column     |            Type             | Modifiers 
---------------+-----------------------------+-----------
 row_id        | character varying           | not null
 registry_id   | integer                     | not null
 row           | character varying           | not null

In real world registries is just a csv-file and rows is lines of the files. In my scala-slick application, I want to know how many lines in each file.

registries:

1,foo,...
2,bar,...
3,baz,...

rows:

aaa,1,...
bbb,1,...
ccc,2,...

desired result:

1,foo,... - 2
2,bar,... - 1
3,baz,... - 0

My code now is (slick-3.0):

def getRegistryWithLength(rId: Int) = {
    val q1 = registries.filter(_.registryId===rId).take(1).result.headOption
    val q2 = rows.filter(_.registryId===rId).length.result
    val registry = Await.result(db.run(q1), 5.seconds)
    val length = Await.result(db.run(q2), 5.seconds)
    (registry, length)
}

(Await is bad idea, I know it)

How can I do getRegistryWithLength using single sql query?

I could add column row_n into table registries, but then I'll be forced to do updating column row_n after delete/insert query of rows table.

How can I do automatic calculation column row_n in table registries on db server side?


回答1:


The basic query could be:

SELECT r.*, COALESCE(n.ct, 0) AS ct
FROM   registry r
LEFT   JOIN (
   SELECT registry_id, count(*) AS ct
   FROM   rows
   GROUP  BY registry_id
   ) n USING (registry_id);

The LEFT [OUTER] JOIN is essential so you do not filter rows from registry without related rows in rows.

COALESCE to return 0 instead of NULL where no related rows are found.

There are many related answers on SO. One here:

  • SQL: How to save order in sql query?

You could wrap this in a VIEW for convenience:

CREATE VIEW reg_rn AS
SELECT ...

... which you query like a table.

Aside: It's unwise to use reserved SQL key words as identifiers. row is a no-go for a column name (even if allowed in Postgres).




回答2:


Thanks Erwin Brandstetter for awesome answer, using it, I wrote code for my scala-slick application.

Scala code looks much more complicated than plain sql:

val registryQuery = registries.filter(_.userId === userId)
val rowQuery = rows groupBy(_.registryId) map { case (regId, rowItems) => (regId, rowItems.length)}
val q = registryQuery joinLeft rowQuery on (_.registryId === _._1) map {
  case (registry, rowsCnt) => (registry, rowsCnt.map(_._2))
}

but it works!



来源:https://stackoverflow.com/questions/32505454/calculate-table-column-using-over-table-on-server-side

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!