4

I have this table

 ID    value    user      stock
----|--------|---------|---------
  1 |   10   | mark    |  AAPL
  2 |   20   | rob     |  GOOG
  3 |   30   | mark    |  AAPL
  4 |  -40   | mark    |  AAPL
  5 |  -10   | rob     |  GOOG
  6 |   25   | mark    |  GOOG
  7 |    5   | mark    |  GOOG
  8 |   45   | mark    |  AAPL

I would like to build a query (possibly without using any PGSQL function) that returns the rows shown below. It should start in order (ID ASC) summing "value" column grouped by user,stock. If the temporary sum is 0, all the previous rows (for that group) will be discarded.

 id    value    user      stock
----|--------|---------|---------
  2 |   20   | rob     |  GOOG
  5 |  -10   | rob     |  GOOG
  6 |   25   | mark    |  GOOG
  7 |    5   | mark    |  GOOG
  8 |   45   | mark    |  AAPL

I think that OVER (PARTITION BY) and WINDOW function should be used SELECT *, SUM(value) OVER w AS scm FROM "mytable" WINDOW w AS (PARTITION BY user,stock ORDER BY id ASC)

this returns next table

 ID    value    user      stock    scm
----|--------|---------|---------|-------
  1 |   10   | mark    |  AAPL   | 10
  2 |   20   | rob     |  GOOG   | 20
  3 |   30   | mark    |  AAPL   | 40
  4 |  -40   | mark    |  AAPL   |  0
  5 |  -10   | rob     |  GOOG   | 10
  6 |   25   | mark    |  GOOG   | 25
  7 |    5   | mark    |  GOOG   | 30
  8 |   45   | mark    |  AAPL   | 45

So this should be a good starting point, because it shows that APPL for mark is 0 (id=4) and for that group (AAPL,mark) I should keep all the following rows. The rule is: for each group (stock,user) keep all the rows following the last row with scm=0

4

2 回答 2

1

SQL小提琴

with s as (
    select *,
        count(scm = 0 or null) over w z
    from (
        select *,
            sum(value) over w as scm
        from mytable
        window w as (partition by "user", stock order by id asc)
    ) s
    window w as (partition by "user", stock order by id asc)
)
select *
from
    s
    inner join
    (
        select max(z) z, "user", stock
        from s
        group by "user", stock
    ) z using (z, "user", stock)
where scm > 0
order by s.user, s.stock, id
于 2013-04-17T16:00:31.493 回答
0

我认为像下面这样的东西会让你想要你想要的。基本上它将执行以下操作:

  1. 使用您必须计算累积和的 SQL 语句。
  2. 计算应为每个(username, stock)组显示的最小 ID。
  3. 从原始 SQL 累积总和中选择并过滤掉任何低于最小 ID 的 ID。
WITH sums AS (
  SELECT id, value, username, stock, SUM(value) OVER w AS scm
    FROM "mytable"
  WINDOW w AS (PARTITION BY user,stock ORDER BY id ASC)),

minimum_ids AS (
  SELECT username, stock, MAX(id) as minimum_id
    FROM sums
   WHERE scm <= 0
   GROUP BY username, stock)

SELECT sums.id, sums.value, sums.username, sums.stock, sums.scm
  FROM sums
  LEFT JOIN minimum_ids
    ON (sums.username = minimum_ids.username
        AND sums.stock = minimum_ids.stock)
 WHERE (minimum_ids.minimum_id IS NULL OR sums.id > minimum_ids.minimum_id)
 ORDER BY id;
于 2013-04-17T15:59:03.620 回答