简体   繁体   中英

Sum multiple rows while writing a query SQL

The query I am using is below:

SELECT
    b.partyID, 
    (select top 1 b.credit) as opening,
    case when (b.total>b.credit) then  b.price else '0' end as debit,
    case when (b.total<b.credit) then b.price else '0' end as credit,
    (select top 1 b.total) as closing
FROM tblPartyOrder b 
WHERE b.date>='2014-03-06' AND b.date<='2016-03-09'
GROUP BY b.partyID, b.credit, b.total, b.price
ORDER BY b.partyID;

Result from query:

结果

What I need:

  1. There should be one row for each partyID;
  2. Keep only the first value as opening (Opening balance as in accounting);
  3. I want to sum the rows debit credit;
  4. Keep only last value in closing (closing balance as in accounting).

Please help! Much obliged.

To do that, you should first create a view party_table_view to add a rownumber for each group of partyID like this :

SELECT  ROW_NUMBER() OVER (PARTITION BY partyID order by partyID) as ligne,  partyID , opening, debit, credit,closing 
FROM dbo.party_table

second, you execute the following query :

select 
 a.partyID,
(select top 1 b.opening FROM party_table_view as b where a.partyID=b.partyID) as op,
SUM(a.debit),
SUM(a.credit),
(select top 1 c.closing FROM party_table_view as c 
         where a.partyID=c.partyID 
         and 
         (select COUNT(*) FROM party_table_view as d where c.partyID=d.partyID)
          =
          c.ligne
  ) as cl FROM party_table_view as a GROUP BY a.partyID ORDER BY a.partyID;

and here is the result as you wanted

Result

enjoy :D !

You group by b.partyID, b.credit, b.total, b.price. This means you get one result row per b.partyID, b.credit, b.total, b.price.

Let's say these are your table's records:

partyID  credit  price  total  date
1        10      20     30     2015-10-01
1        30      20     10     2015-10-02
1        10      20     30     2015-10-03
1        30      20     50     2015-10-04
2        10      20     30     2015-10-01

then you'll get (which you could also have got with DISTINCT, as you are not using any aggregate functions):

GROUP BY clause applied:

partyID  credit  price  total
1        10      20     30
1        30      20     10
1        30      20     50
2        10      20     30

SELECT clause applied:

partyID  opening  debit  credit  closing
1        10        20    0       30
1        30        0     20      10
1        30        20    0       50
2        10        20    0       30

In your SELECT clause you are using subqueries such as (select top 1 b.credit) . So you are saying: "Give me one record. Of all these one records (sic) give me the top one by whatever order you like (TOP without ORDER BY). Fill this record with one value. This one value is to be b.credit ."

b.credit is in the GROUP BY clause, so there is only one value per group. You can easily replace the whole subquery (select top 1 b.credit) with a mere b.credit .

Here is your query re-written:

SELECT distinct
  b.partyID, 
  b.credit as opening,
  case when b.total > b.credit then b.price else 0 end as debit,
  case when b.total < b.credit then b.price else 0 end as credit,
  b.total as closing
FROM tblPartyOrder b
WHERE b.date >= '2014-03-06' and b.date <= '2016-03-09'
ORDER BY b.partyID;

Now to your actual problem: You want one row per partyID , so group by partyID (only). You want a sum, so use the aggregate function SUM . You want to find the first and last record per partyID, so mark them somehow. You can use the analytic function ROW_NUMBER for this, giving these records the #1:

select
  partyid,
  min(case when first_is_one = 1 then credit end) as opening,
  sum(case when total > credit then price else 0 end) as debit,
  sum(case when total < credit then price else 0 end) as credit, 
  min(case when last_is_one = 1 then total end) as closing
from
(
  select
    po.partyid, po.credit, po.total, po.price,
    row_number() over (partition by po.partyid order by po.date) as first_is_one,
    row_number() over (partition by po.partyid order by po.date desc) as last_is_one
  from tblpartyorder po
  where po.date >= '2014-03-06' and po.date <= '2016-03-09'
) marked
group by partyid
order by partyid;

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM