【问题标题】:Complex SQL query help on aggregating values for nested subquery为嵌套子查询聚合值的复杂 SQL 查询帮助
【发布时间】:2010-03-12 04:59:42
【问题描述】:

我有人员、公司、员工、事件和事件类型。我正在制作一个报告/跟进表,其中人员、公司和员工是行,列是事件类型。

事件种类是简单的值描述:“承诺的捐赠”、“收到的捐赠”、“电话”、“跟进”等。事件种类排序:

CREATE TABLE event_kinds (
  id,
  name,
  position);

Events 持有对事件的实际引用:

CREATE TABLE events (
  id,
  person_id,
  company_id,
  referrer_id,
  event_kind_id,
  created_at);

referrer_id 是对人的另一个引用。它是发送信息/提示的人,并且是一个可选字段,尽管我有时想过滤具有特定引荐来源的 event_kind,而我不过滤其他事件类型。

请注意,我没有员工 ID 参考。引用存在,但被暗示。我有应用程序代码来验证 person_id 和 company_id 确实引用了员工记录。其他表非常基本:

CREATE TABLE people (
  id, name);

CREATE TABLE companies (
  id, name);

CREATE TABLE employees (
  id, person_id, company_id);

我正在努力实现以下报告:

推荐人 打电话 承诺 捐赠 弗朗索瓦 2 月 16 日 2 月 20 日 3 月 1 日 苹果(史蒂夫·乔布斯)史蒂夫·鲍尔默 3 月 3 日 IBM 比尔盖茨 3 月 7 日

第一行是人员记录,第二行是员工,第三行是公司。如果我向 Bill Gates 询问 Phoned 事件类型,我只会看到第 3 行,而询问 Steve 和 Phoned 则不会返回任何行。

现在,我做了 3 个查询,一个是针对公司的,一个是针对人员的,最后一个是针对员工的。我希望对事件类型列进行排序,但我在应用程序代码中这样做并在那里正确显示。这是我目前所处的位置:

SELECT companies.id,
       companies.name,
       (SELECT events.id FROM events WHERE events.referrer_id = 1470 AND events.company_id = companies.id AND events.person_id IS NULL AND events.event_kind_id = 9 ORDER BY created_at DESC LIMIT 1) event_kind_9,
       (SELECT events.id FROM events WHERE events.company_id = companies.id AND events.person_id IS NULL AND events.event_kind_id = 10 ORDER BY created_at DESC LIMIT 1) event_kind_10,
       (SELECT events.created_at FROM events WHERE events.referrer_id = 1470 AND events.company_id = companies.id AND events.person_id IS NULL AND events.event_kind_id = 9 ORDER BY created_at DESC LIMIT 1) event_kind_9_order
FROM "companies"

SELECT people.id,
       people.name,
       (SELECT events.id FROM events WHERE events.referrer_id = 1470 AND events.company_id IS NULL AND events.person_id = people.id AND events.event_kind_id = 9 ORDER BY created_at DESC LIMIT 1) event_kind_9,
       (SELECT events.id FROM events WHERE events.company_id IS NULL AND events.person_id = people.id AND events.event_kind_id = 10 ORDER BY created_at DESC LIMIT 1) event_kind_10,
       (SELECT events.created_at FROM events WHERE events.referrer_id = 1470 AND events.company_id IS NULL AND events.person_id = people.id AND events.event_kind_id = 9 ORDER BY created_at DESC LIMIT 1) event_kind_9_order
FROM "people"

SELECT employees.id,
       employees.company_id,
       employees.person_id,
       (SELECT events.id FROM events WHERE events.referrer_id = 1470 AND events.company_id = employees.company_id AND events.person_id = employees.person_id AND events.event_kind_id = 9 ORDER BY created_at DESC LIMIT 1) event_kind_9,
       (SELECT events.id FROM events WHERE events.company_id = employees.company_id AND events.person_id = employees.person_id AND events.event_kind_id = 10 ORDER BY created_at DESC LIMIT 1) event_kind_10,
       (SELECT events.created_at FROM events WHERE events.referrer_id = 1470 AND events.company_id = employees.company_id AND events.person_id = employees.person_id AND events.event_kind_id = 9 ORDER BY created_at DESC LIMIT 1) event_kind_9_order
FROM "employees"

我宁愿怀疑我做错了。应该有一种“更简单”的方法来做到这一点。

另一个过滤条件是过滤人员/公司名称:WHERE LOWER(companies.name) LIKE '%apple%'。

请注意,我在这里按 event_kind_9 的日期排序,次要排序是按个人/公司名称。

总结一下:我想对结果集进行分页,找到每个单元格的最新事件,按最新事件的日期和公司/人名对结果集进行排序,在某些事件类型中按推荐人过滤,但是不是其他人。

作为参考,我正在使用来自 Ruby、ActiveRecord/Rails 的 PostgreSQL。解决方案是纯 SQL。

【问题讨论】:

    标签: sql postgresql


    【解决方案1】:

    同一个人/公司和 event_kind_id 是否可以有多个行(例如,比尔·盖茨在 3 月 7 日和 3 月 9 日打电话)?如果没有,您可以执行以下操作:

    Select Coalesce(People.name, Companies.name) As Name
        , Referrers.name
        , Min(Case When EventKinds.name = 'Phoned' Then Events.created_at End) As Phoned
        , Min(Case When EventKinds.name = 'Promised' Then Events.created_at End) As Promised
        , Min(Case When EventKinds.name = 'Donated' Then Events.created_at End) As Donated
    From Events
        Join EventKinds
            On EventKinds.id = Events.event_kind_id
        Left Join People As Referrers
            On Referrers.id = Events.referrer_id
        Left Join People
            On People.id = Events.person_id
        Left Join Companies
            On Companies.id = Events.company_id
    -- Where Companies.Name Like 'foo%'
    Group By Coalesce(People.name, Companies.name), Referrers.name
    

    【讨论】:

    • 我只需要每种事件类型的最新事件。很抱歉迟到了。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2018-07-29
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-08-27
    • 1970-01-01
    相关资源
    最近更新 更多