简体   繁体   中英

Combine data from a table to one row T-SQL

I have a table in #SQL server 2008 that has transaction data. The table looks like this. I would like to have this in a sql statement.

TransactionId|TransactionDate|TransactionType|Amount|Balance|UserId

The transaction type can be one of four types, Deposit, Withdrawals, Profit and Stake. I give an example how it can look like in the transaction table. The balance is the Sum of amount column.

TransactionId|TransactionDate|TransactionType|Amount|Balance|UserId
1|             2013-03-25|      Deposit|         150|    150|     1
2|             2013-03-27|      Stake|           -20|    130|     1
3|             2013-03-28|      Profit |         1500|   1630|    1
4 |            2013-03-29|      Withdrawals|     -700|   930|     1
5|             2013-03-29|      Stake |          -230 |  700 |    1
6|             2013-04-04|      Stake|           -150 |  550|     1
7|             2013-04-06|      Stake |          -150 |  400|     1

What I want now is to get a select statement that gives me all data grouped by week. The result should look like this.

Week|Deposit|Withdrawals|Stake|Profit|Balance|Year
13 |  150|     -700  |      -250 | 1500 |  700 |    2013
14 |  0  |     0     |      -300|  0   |   400 |    2013

I have also problem with the weeks... I live in Europe an my first day in a week is monday. I have a solution for that but around the end of a year I get sometimes week 54 but there are only 52 weeks in a year...

I hope someone can help me out.

This is what I have so far.

SELECT transactionid, 
       transactiondate, 
       transactiontype, 
       amount, 
       (SELECT Sum(amount) 
        FROM   transactions AS trans_ 
        WHERE  trans_.transactiondate <= trans.transactiondate 
               AND userid = 1)         AS Balance, 
       userid, 
       Datepart(week, transactiondate) AS Week, 
       Datepart(year, transactiondate) AS Year 
FROM   transactions trans 
WHERE  userid = 1 
ORDER  BY transactiondate DESC, 
          transactionid DESC 

Here's sample data and my query on sql-fiddle: http://www.sqlfiddle.com/#!3/79d65/92/0

In order to transform the data from the rows into columns, you will want to use the PIVOT function.

You did not specify what balance value you want to return but based on the final result, it looks like you want the final balance to be the value associated with the last transaction date for each day. If that is not correct, then please clarify what the logic should be.

In order to get the result you will want to use the DATEPART and YEAR functions. These will allow grouping by both the week and year values.

The following query should get the result that you want:

select week, 
  coalesce(Deposit, 0) Deposit, 
  coalesce(Withdrawals, 0) Withdrawals, 
  coalesce(Stake, 0) Stake, 
  coalesce(Profit, 0) Profit,
  Balance,
  Year
from
(
  select datepart(week, t1.transactiondate) week,
    t1.transactiontype,
    t2.balance,
    t1.amount,
    year(t1.transactiondate) year
  from transactions t1
  cross apply
  (
    select top 1 balance 
    from transactions t2
    where datepart(week, t1.transactiondate) = datepart(week,  t2.transactiondate)
      and year(t1.transactiondate) = year(t2.transactiondate)
      and t1.userid = t2.userid
    order by TransactionId desc
  ) t2
) d
pivot
(
  sum(amount)
  for transactiontype in (Deposit, Withdrawals, Stake, Profit)
) piv;

See SQL Fiddle with Demo . The result is:

| WEEK | DEPOSIT | WITHDRAWALS | STAKE | PROFIT | BALANCE | YEAR |
------------------------------------------------------------------
|   13 |     150 |        -700 |  -250 |   1500 |     700 | 2013 |
|   14 |       0 |           0 |  -300 |      0 |     400 | 2013 |

As a side note, you stated that your start of the week is Monday, you might have to use the DATEFIRST function to set the first day of the week.

Another option, without using PIVOT, but rather with few CASEs

WITH CTE AS
(
    SELECT
         TransactionId 
        ,TransactionDate
        ,DATEPART(WEEK, TransactionDate) AS Week
        ,CASE WHEN TransactionType='Deposit' THEN Amount ELSE 0 END AS Deposit 
        ,CASE WHEN TransactionType='Stake' THEN Amount ELSE 0 END AS Stake 
        ,CASE WHEN TransactionType='Profit' THEN Amount ELSE 0 END AS Profit 
        ,CASE WHEN TransactionType='Withdrawals' THEN Amount ELSE 0 END AS Withdrawals 
        ,Balance
        ,DATEPART(YEAR, TransactionDate) AS Year
    FROM dbo.Transactions
)
SELECT 
  Week,  SUM(Deposit) AS Deposit, SUM(Withdrawals) AS Withdrawals, SUM(Stake) AS Stake, SUM(Profit) AS Profit, 
    (SELECT Balance FROM CTE i WHERE i.TransactionID = MAX(o.TransactionID)) AS BAlance, Year
FROM CTE o
GROUP BY Week, Year

SQLFiddle Demo

http://www.sqlfiddle.com/#!3/79d65/89

;WITH cte AS
(
  SELECT datepart(ww, transactiondate) wk,
  sum(CASE WHEN TransactionType = 'Deposit' THEN Amount ELSE 0 END) AS D,
  sum(CASE WHEN TransactionType = 'Withdrawals' THEN Amount ELSE 0 END)  AS W,
  sum(CASE WHEN TransactionType = 'Profit' THEN Amount ELSE 0 END) AS P,
  sum(CASE WHEN TransactionType = 'Stake' THEN Amount ELSE 0 END)  AS S,
  sum(
    CASE WHEN TransactionType = 'Deposit' THEN Amount ELSE 0 END +
    CASE WHEN TransactionType = 'Withdrawals' THEN Amount ELSE 0 END +
    CASE WHEN TransactionType = 'Profit' THEN Amount ELSE 0 END +
    CASE WHEN TransactionType = 'Stake' THEN Amount ELSE 0 END +
    CASE WHEN TransactionType = 'Balance' THEN Amount ELSE 0 END) AS wkTotal
  FROM transactions
  GROUP BY datepart(ww, transactiondate)),
  cte1 AS
  (
    SELECT *, row_number() over (ORDER BY wk) AS rowNum
    FROM cte)
  SELECT wk, d, w, p, s, wktotal
  + coalesce((SELECT top 1 wktotal FROM cte1 x WHERE x.rownum < m.rownum ), 0) AS RunningBalance
FROM cte1 m

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