Sql 查询返回与逗号分隔字符串具有相同 ID 的元素

发布于 2024-12-05 00:08:29 字数 1557 浏览 1 评论 0原文

我有两个表,table1entry_IDentry_date和其他条目信息。 table2 具有 entry_IDentry_subject。每个entry_ID可以有任意多个entry_subjects

我想要一个查询,该查询将返回 entry_IDentry_date 以及与该条目对应的主题列表,以逗号分隔。

第一步似乎只是获取一个返回 entry_ID 和来自 table2 的以逗号分隔的主题列表的查询。一旦我知道加入应该很容易。
我改编了此站点的递归 CTE 方法:以适合我的情况:

WITH RECURSIVE CTE (entry_ID, subjectlist, subject, length)
    AS ( SELECT entry_ID, cast( '' as varchar(8000))
                        , cast( '' as varchar(8000)), 0
         FROM table2 
         GROUP BY entry_ID
         UNION ALL 
         SELECT t2.entry_ID, 
             cast(subjectlist || CASE length = 0 THEN '' ELSE ', ' END
                              || entry_subject AS varchar(8000) ),
             cast (t2.entry_subject as varchar(8000)),
             length +1
         FROM CTE c 
         INNER JOIN table2 t2 
             on c.entry_ID=t2.entry_ID where t2.entry_subject > c.subject)
SELECT entry_ID, subjectlist FROM (
    SELECT entry_ID, subjectlist, RANK() OVER (
        PARTITION BY entry_ID order by length DESC)
    FROM CTE) D (entry_ID, subjectlist, rank) where rank = 1;

并且它有效,我得到了我所期望的回应。为了实现我的最终目标,我使用的查询是这样的:

SELECT t1.* t2.subjectlist FROM table1 
    JOIN (ABOVE QUERY) AS t2 on t1.entry_ID=t2.entry_ID; 

这看起来非常笨拙。这真的是最好的方法吗?

I have two tables, table1 has a entry_ID, entry_date and other entry information. table2 has entry_ID and entry_subject. Each entry_ID can have arbitrarily many entry_subjects.

I want a query that will return an entry_ID, entry_date, and a list of the subjects corresponding to that entry separated by commas.

The first step in this seems to be just getting a query that returns an entry_ID and a comma separated list of subjects from table2. Once I have that the join should be easy.
I adapted the recursive CTE method from this site: to fit my case:

WITH RECURSIVE CTE (entry_ID, subjectlist, subject, length)
    AS ( SELECT entry_ID, cast( '' as varchar(8000))
                        , cast( '' as varchar(8000)), 0
         FROM table2 
         GROUP BY entry_ID
         UNION ALL 
         SELECT t2.entry_ID, 
             cast(subjectlist || CASE length = 0 THEN '' ELSE ', ' END
                              || entry_subject AS varchar(8000) ),
             cast (t2.entry_subject as varchar(8000)),
             length +1
         FROM CTE c 
         INNER JOIN table2 t2 
             on c.entry_ID=t2.entry_ID where t2.entry_subject > c.subject)
SELECT entry_ID, subjectlist FROM (
    SELECT entry_ID, subjectlist, RANK() OVER (
        PARTITION BY entry_ID order by length DESC)
    FROM CTE) D (entry_ID, subjectlist, rank) where rank = 1;

And it works, I get the response I expect. To achieve my final goal the query I use is this:

SELECT t1.* t2.subjectlist FROM table1 
    JOIN (ABOVE QUERY) AS t2 on t1.entry_ID=t2.entry_ID; 

This seems very unwieldy. Is this really the best way to do this?

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

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

发布评论

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

评论(1

萌︼了一个春 2024-12-12 00:08:29

如果我理解正确,那么应该有一个更简单的解决方案。

测试设置

根据您的描述 - 您可以为我们这样做:

CREATE TABLE table1 (
   entry_id int4 PRIMARY KEY
 , entry_date date
);

CREATE TABLE table2 (
   entry_id int4 REFERENCES table1 (entry_id)
 , entry_subject text
 , PRIMARY KEY (entry_id, entry_subject)
);

INSERT INTO table1 VALUES (1, '2011-09-01'), (2, '2011-09-02'),(3, '2011-09-03');
INSERT INTO table2 VALUES (1, 'foo1'), (2, 'foo2'), (2, 'bar2')
                        , (3, 'foo3'), (3, 'baz3'), (3, 'bar3');  

回答

string_agg() 需要 Postgres 9.0+

SELECT t1.entry_id, t1.entry_date
     , string_agg(t2.entry_subject, ', ') AS entry_subjects
FROM   table1 t1
JOIN   table2 t2 USING (entry_id)
GROUP  BY 1,2
ORDER  BY 1;

 entry_id | entry_date | entry_subjects
----------+------------+------------------
        1 | 2011-09-01 | foo1
        2 | 2011-09-02 | bar2, foo2
        3 | 2011-09-03 | baz3, bar3, foo3

或者,如果您想要对 Entry_subjects 排序

SELECT DISTINCT ON (1)
       t1.entry_id
     , t1.entry_date
     , string_agg(t2.entry_subject, ', ') OVER (
          PARTITION BY t1.entry_id ORDER BY t2.entry_subject
          RANGE BETWEEN UNBOUNDED PRECEDING
                    AND UNBOUNDED FOLLOWING) AS entry_subjects
  FROM table1 t1
  JOIN table2 t2 USING (entry_id)
  ORDER BY 1;

 entry_id | entry_date | entry_subjects
----------+------------+------------------
        1 | 2011-09-01 | foo1
        2 | 2011-09-02 | bar2, foo2
        3 | 2011-09-03 | bar3, baz3, foo3

您可以执行以下操作与在 table2 上对第一个 ORDER BY entry_subject 进行子选择相同。

If I understand correctly, then there should be a much simpler solution.

Test setup

According to your description - you could have done that for us:

CREATE TABLE table1 (
   entry_id int4 PRIMARY KEY
 , entry_date date
);

CREATE TABLE table2 (
   entry_id int4 REFERENCES table1 (entry_id)
 , entry_subject text
 , PRIMARY KEY (entry_id, entry_subject)
);

INSERT INTO table1 VALUES (1, '2011-09-01'), (2, '2011-09-02'),(3, '2011-09-03');
INSERT INTO table2 VALUES (1, 'foo1'), (2, 'foo2'), (2, 'bar2')
                        , (3, 'foo3'), (3, 'baz3'), (3, 'bar3');  

Answer

string_agg() requires Postgres 9.0+

SELECT t1.entry_id, t1.entry_date
     , string_agg(t2.entry_subject, ', ') AS entry_subjects
FROM   table1 t1
JOIN   table2 t2 USING (entry_id)
GROUP  BY 1,2
ORDER  BY 1;

 entry_id | entry_date | entry_subjects
----------+------------+------------------
        1 | 2011-09-01 | foo1
        2 | 2011-09-02 | bar2, foo2
        3 | 2011-09-03 | baz3, bar3, foo3

Or, if you want the entry_subjects sorted:

SELECT DISTINCT ON (1)
       t1.entry_id
     , t1.entry_date
     , string_agg(t2.entry_subject, ', ') OVER (
          PARTITION BY t1.entry_id ORDER BY t2.entry_subject
          RANGE BETWEEN UNBOUNDED PRECEDING
                    AND UNBOUNDED FOLLOWING) AS entry_subjects
  FROM table1 t1
  JOIN table2 t2 USING (entry_id)
  ORDER BY 1;

 entry_id | entry_date | entry_subjects
----------+------------+------------------
        1 | 2011-09-01 | foo1
        2 | 2011-09-02 | bar2, foo2
        3 | 2011-09-03 | bar3, baz3, foo3

You could do the same with a subselect on table2 to first ORDER BY entry_subject.

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