2

SOLUTION

I solved it by simple doing the following.

SELECT table_size, sum(cost) as total_cost, sum(num_players) as num_players
FROM
(
  SELECT table_size, cost, sum(tp.uid) as num_players
  FROM tournament as t
  LEFT JOIN takes_part AS tp ON tp.tid = t.tid
  LEFT JOIN users as u on u.uid = tp.tid
  JOIN attributes as a on a.aid = t.attrId
  GROUP BY t.tid
) as res
GROUP BY table_size

I wasn't sure it would work, what with the other aggregate functions that I had to use in my real sql, but it seems to be working ok. There may be problems in the future if I want to do other kind of calculations, for instance do a COUNT(DISTINCT tp.uid) over all tournaments. Still, in this case that is not all that important so I am satisfied for now. Thank you all for your help.

UPDATE!!! Here is a Fiddle that explains the problem: http://www.sqlfiddle.com/#!2/e03ff/7

I want to get:

table_size  |  cost
-------------------------------
5           |  110
8           |   80

OLD POST

I'm sure that there is an easy solution to this that I'm just not seeing, but I can't seem to find a solution to it anywhere. What I'm trying to do is the following:

I need to sum 'costs' per tournament in a system. For other reasons, I've had to join with lots of other tables, making the same cost appear on multiple rows, like so:

id | name | cost | (hidden_id)
-----------------------------
0  | Abc  | 100  | 1
1  | ASD  | 100  | 1
2  | Das  | 100  | 1
3  | Ads  |  50  | 2
4  | Ads  |  50  | 2
5  | Fsd  |   0  | 3
6  | Ads  |   0  | 3
7  | Dsa  |   0  | 3

The costs in the table above are linked to an id value that is not necessary selected in by the SQL (this depends on what the user decides at runtime). What I want to get, is the sum 100+50+0 = 150. Of course, if I just use SUM(cost) I will get a different answer. I tried using SUM(cost)/COUNT(*)*COUNT(tourney_ids) but this only gives correct result under certain circumstances. A (very) simple form of query looks like this:

SELECT SUM(cost) as tot_cost -- This will not work as it sums all rows where the sum appears.
FROM t
JOIN ta ON t.attr_id = ta.toaid
JOIN tr ON tr.toid = t.toid  -- This row will cause multiple rows with same cost
GROUP BY *selected by user*  -- This row enables the user to group by several attributes, such as weekday, hour or ids of different kinds.

UPDATE. A more correct SQL-query, perhaps:

SELECT
*some way to sum cost*
FROM tournament AS t
JOIN attribute AS ta ON t.attr_id = ta.toaid
JOIN registration AS tr ON tr.tourneyId = t.tourneyId
INNER JOIN pokerstuff as ga ON ta.game_attr_id = ga.gameId
LEFT JOIN people AS p ON p.userId = tr.userId
LEFT JOIN parttaking AS jlt ON (jlt.tourneyId = t.tourneyId AND tr.userId = jlt.userId)
LEFT JOIN (
    SELECT t.tourneyId,
    ta.a - (ta.b) - sum(c)*ta.cost AS cost
    FROM tournament as t
    JOIN attribute as ta ON (t.attr_id = ta.toaid)
    JOIN registration tr ON (tr.tourneyId = t.tourneyId)
    GROUP BY t.tourneyId, ta.b, ta.a
) as o on t.tourneyId = o.tourneyId
AND whereConditions
GROUP BY groupBySql

Description of the tables

  • tournament (tourneyId, name, attributeId)
  • attributes (attributeId, ..., gameid)
  • registration (userId, tourneyId, ...)
  • pokerstuff(gameid,...)
  • people(userId,...)
  • parttaking(userId, tourneyId,...)

Let's assume that we have the following (cost is actually calculated in a subquery, but since it's tied to tournament, I will treat it as an attribute here):

tournament:

tourneyId | name         | cost
1         | MyTournament |  50
2         | MyTournament |  80

and

userId | tourneyId
1      | 1
2      | 1
3      | 1
4      | 1
1      | 2
4      | 2

The problem is rather simple. I need to be able to get the sum of the costs of the tournaments without counting a tournament more than once. The sum (and all other aggregates) will be dynamically grouped by the user.

A big problem is that many solutions that I've tried (such as SUM OVER...) would require that I group by certain attributes, and that I cannot do. The group by-clause must be completely decided by the user. The sum of the cost should sum over any group-by attributes, the only problem is of course the multiple rows in which the sum appears.

Do anyone of you have any good hints on what can be done?

4

3 回答 3

1

尝试以下操作:

select *selected by user*, sum(case rownum when 1 then a.cost end)
from
(
    select
        *selected by user*, cost,
        row_number() over (partition by t.tid) as rownum
    FROM t
    JOIN ta ON t.attr_id = ta.toaid
    JOIN tr ON tr.toid = t.toid
) a
group by *selected by user*

row_number 用于对具有相同锦标赛行的每一行进行编号。在对成本求和时,我们只考虑那些 rownum 为 1 的行。所有其他行在成本方面都是这一行的副本。


就小提琴而言:

select table_size, sum(case rownum when 1 then a.cost end)
from
(
  SELECT
      table_size, cost,
      row_number() over (partition by t.tid) as rownum
  FROM tournament as t
  LEFT JOIN takes_part AS tp ON tp.tid = t.tid
  LEFT JOIN users as u on u.uid = tp.tid
  JOIN attributes as a on a.aid = t.attrId
) a
group by table_size
于 2013-04-22T10:17:16.417 回答
0

由于每次重复成本都是相同的,因此您可以通过隐藏 id 对它们进行平均并执行以下操作:

WITH MrTable AS (
  SELECT DISTINCT hidden_id, AVG(cost) OVER (PARTITION BY hidden_id) AS cost
  FROM stuff
)
SELECT SUM(cost) FROM MrTable;
于 2013-04-22T11:44:36.453 回答
0

(更新)鉴于当前返回的成本是每次锦标赛的总成本,您可以在内部选择的每一行上包含成本的小数值,这样所有这些值的总和就等于总成本(允许事实上,每个给定锦标赛的值可能会出现多次),然后在您的外部选择中将分数成本相加,如下所示:

select table_size, sum(frac_cost) as agg_cost from
(SELECT a.table_size , cost / count(*) over (partition by t.tid) as frac_cost
 FROM tournament as t
 LEFT JOIN takes_part AS tp ON tp.tid = t.tid
 LEFT JOIN users as u on u.uid = tp.uid
 JOIN attributes as a on a.aid = t.attrId) sq
GROUP BY table_size

SQLFiddle在这里

于 2013-04-22T13:07:38.780 回答