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 に答える