I have a table of Account Transactions that includes ID, Amount, Date. Basically, I want to create a resulting table that looks at the table and returns what the SUM was for the Account over three different Ending Date Ranges. Then I want to Flag (Combined_Flag) each Account ID, 1 if any of the SUMs for that ID are non-zero, and a 0 if all of the SUMs are 0.
Date Range 1) Min Date to End of Last Month (-1 Month)
Date Range 2) Min Date to End of 2 Months ago (-2 Months)
Date Range 3) Min Date to End of Last Month, Last Year (-13 Months)
The Resulting table should be: ID, SUM_R1, SUM_R2, SUM_R3, Flag_R1, Flag_R2, Flag_R3, Combined_Flag
Example Data
| ID | Amount | Date |
| -------- | -------------- |-------------- |
| 1 | 20 | 09/01/19 |
| 2 | 40 | 09/01/19 |
| 3 | 0 | 09/01/19 |
| 4 | 0 | 09/01/19 |
| 1 | 10 | 10/01/19 |
| 2 | 0 | 10/01/19 |
| 3 | 0 | 10/01/19 |
| 4 | 0 | 10/01/19 |
| 1 | 15 | 11/01/19 |
| 2 | 40 | 11/01/19 |
| 3 | 0 | 11/01/19 |
| 4 | 0 | 11/01/19 |
| 1 | 20 | 09/01/20 |
| 2 | 40 | 09/01/20 |
| 3 | 0 | 09/01/20 |
| 4 | 50 | 09/01/20 |
| 1 | 10 | 10/01/20 |
| 2 | 0 | 10/01/20 |
| 3 | 0 | 10/01/20 |
| 4 | 65 | 10/01/20 |
| 1 | 15 | 11/01/20 |
| 2 | 40 | 11/01/20 |
| 3 | 0 | 11/01/20 |
| 4 | 0 | 11/01/20 |
Expected Result Table (Using Date of 12/21/2020)
| ID | SUM_R1 | SUM_R2 | SUM_R3 | Flag_R1 | Flag_R2 | Flag_R3 | Combined_Flag |
| -------- | -------- | -------- | -------- | --------- | --------- | --------- | --------------- |
| 1 | 90 | 75 | 45 | 1 | 1 | 1 | 1 |
| 2 | 160 | 120 | 80 | 1 | 1 | 1 | 1 |
| 3 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
| 4 | 115 | 115 | 0 | 1 | 1 | 0 | 1 |
The difficulty I'm having is in joining the table basically to itself 2 times. I'm getting results all over the place and not really sure exactly what's going on.
Is this what you want?
select id,
sum(case when date < datefromparts(year(v.dte), month(v.dte), 1)
then amount else 0
end) as sum_r1,
sum(case when date < dateadd(month, -1, datefromparts(year(v.dte), month(v.dte), 1))
then amount else 0
end) as sum_r2,
sum(case when date < dateadd(month, -13, datefromparts(year(v.dte), month(v.dte), 1))
then amount else 0
end) as sum_r3,
max(case when amount > 0 and date < datefromparts(year(v.dte), month(v.dte), 1)
then 1 else 0
end) as flag_r1,
max(case when amount > 0 and date < dateadd(month, -1, datefromparts(year(v.dte), month(v.dte), 1))
then 1 else 0
end) as flag_r2,
max(case when amount > 0 and date < dateadd(month, -13, datefromparts(year(v.dte), month(v.dte), 1))
then 1 else 0
end) as flag_r3
from t cross join
(values (convert(date, '2020-12-21'))
) v(dte)
group by id;
The flag columns assume that the amounts are never negative (which is consistent with the data in your question.
EDIT:
The shorthand in the comment for creating the flag looks like:
abs(sign(sum(case when amount > 0 and date < datefromparts(year(v.dte), month(v.dte), 1)
then amount else 0
end))) as flag_r1,
Here is a db<>fiddle.
Related
I have a table "MyTable" with an id and two int fields "A" and "B":
MyTable
+-------+-----+-----+
| ID | A | B |
+-------+-----+-----+
| 99 | 0 | 1 |
| 99 | 0 | 1 |
| 99 | 0 | 0 |
| 99 | 1 | 1 |
| 99 | 0 | 1 |
| 100 | 1 | 0 |
| 100 | 0 | 0 |
| 100 | 0 | 0 |
| 444 | 1 | 0 |
| 88 | 0 | 0 |
| 88 | 0 | 0 |
| 88 | 0 | 1 |
+-------+-----+-----+
I'd like a T-SQL query to return a single row for each distinct id, which contains:
each distinct ID
whether there exists a row for that ID with a non-zero value for "a"
whether there exists a row for that ID with a non-zero value for "b"
like so:
+-------+-----+-----+
| ID | A | B |
+-------+-----+-----+
| 99 | 1 | 1 |
| 100 | 1 | 0 |
| 444 | 1 | 0 |
| 88 | 0 | 1 |
+-------+-----+-----+
I can GROUP BY the ID, but I don't know how to create the joins or subqueries on each group to get the desired result.
select id, max(case when A<>0 then 1 else 0 end)A, max(case when B<>0 then 1 else 0 end)B
from mytable
group by id
Or you can just use since your value is 1 and 0. But if value is other than that please use first query.
select id, max(A)A, max(B)B
from mytable
group by id
I've got a table TABLE1 like this:
|--------------|--------------|--------------|
| POS | UNIT | VOLUME |
|--------------|--------------|--------------|
| 1 | M2 | 20 |
| 1 | M2 | 30 |
| 1 | M3 | 40 |
| 2 | M2 | 100 |
| 2 | M3 | 20 |
| 3 | ST | 30 |
| 3 | M2 | 10 |
|--------------|--------------|--------------|
Depending on the value of the column UNIT I want to aggregate as follows (each UNIT becomes a new column with the sum of the according value):
|--------------|--------------|--------------|--------------|
| POS | VOLUME_M2 | VOLUME_M3 | VOLUME_ST |
|--------------|--------------|--------------|--------------|
| 1 | 50 | 40 | 0 |
| 2 | 100 | 20 | 0 |
| 3 | 10 | 0 | 30 |
|--------------|--------------|--------------|--------------|
My Solution is
SELECT POS,
CASE
WHEN UNIT = 'M2'
THEN SUM(VOLUME)
ELSE 0
END AS VOLUME_M2,
CASE
WHEN UNIT = 'M3'
THEN SUM(VOLUME)
ELSE 0
END AS VOLUME_M3,
CASE
WHEN UNIT = 'ST'
THEN SUM(VOLUME)
ELSE 0
END AS VOLUME_S
FROM TABLE1
GROUP BY POS, UNIT
My problem is, that my code does not work if I leave out UNIT in the GROUP BY statement (I either have to use it in my aggregation or in my GROUP BY statement)
Therefore I get something like this:
|--------------|--------------|--------------|--------------|
| POS | VOLUME_M2 | VOLUME_M3 | VOLUME_ST |
|--------------|--------------|--------------|--------------|
| 1 | 50 | 0 | 0 |
| 1 | 0 | 40 | 0 |
| 2 | 0 | 20 | 0 |
| 2 | 100 | 0 | 0 |
| 3 | 10 | 0 | 0 |
| 3 | 0 | 0 | 30 |
|--------------|--------------|--------------|--------------|
Besides, could anyone give me a hint, how it is possible to automatically get this type of result (especially if there are a lot of values for UNIT).
Close. For conditional aggregation, the case expression is an argument to the aggregation function:
SELECT POS,
SUM(CASE WHEN UNIT = 'M2' THEN VOLUME ELSE 0 END) AS VOLUME_M2,
SUM(CASE WHEN UNIT = 'M3' THEN VOLUME ELSE 0 END) AS VOLUME_M3,
SUM(CASE WHEN UNIT = 'ST' THEN VOLUME ELSE 0 END) AS VOLUME_ST
FROM TABLE1
GROUP BY POS;
I want to simply add a column to the results given below that comes from "select count(*) ... group by possession". So it should still retain the same number of rows, and have this added column. I was told to look into a lateral join but I don't understand how to do it especially in the context of my query which has the CTE
QUERY
select
*
from (
with possession_change as (
select
(lag(possession,1) over (order by id)) as last_possession,
possession,
clock
from plays
where
game_id in (583615)
and league = 3
and period in (0,1)
)
select * from possession_change
) stuff
;
RESULTS
last_possession | possession | clock
-----------------+------------+-------
| 0 | 3600
0 | 0 | 3600
0 | 0 | 3600
0 | 0 | 3600
0 | 1 | 3561
1 | 1 | 3561
1 | 1 | 3561
1 | 1 | 3449
1 | 1 | 3449
1 | 0 | 3396
0 | 0 | 3396
0 | 0 | 3396
DESIRED RESULTS
last_possession | possession | clock | possession_count
-----------------+------------+-------
| 0 | 3600 | 7
0 | 0 | 3600 | 7
0 | 0 | 3600 | 7
0 | 0 | 3600 | 7
0 | 1 | 3561 | 5
1 | 1 | 3561 | 5
1 | 1 | 3561 | 5
1 | 1 | 3449 | 5
1 | 1 | 3449 | 5
1 | 0 | 3396 | 7
0 | 0 | 3396 | 7
0 | 0 | 3396 | 7
You can use count over:
select
lag(possession,1) over (order by id) as last_possession,
possession,
clock,
count(*) over (partition by possession) cnt
from plays
where
game_id in (583615)
and league = 3
and period in (0,1)
I am trying to subtract two columns and then count how many have the same difference and put those sums into columns. The sums are of how many have a difference of -3 or more, -2, -1, 0, 1, 2, 3 or more grouped by date.
Query must be executed against a DB2 database.
Data...
------------------------------
| Date | Num 1 | Num 2 |
------------------------------
| 2014-02-11 | 19872 | 19873 |
| 2014-02-11 | 19873 | 19873 |
| 2014-02-12 | 19875 | 19873 |
| 2014-02-13 | 19870 | 19873 |
| 2014-02-13 | 19872 | 19873 |
| 2014-02-14 | 19877 | 19869 |
| 2014-02-14 | 19873 | 19873 |
Desired Output...
-----------------------------------------------------------------------
| Date | <= -3 | -2 | -1 | 0 | +1 | +2 | >= +3 |
-----------------------------------------------------------------------
| 2014-02-11 | 0 | 0 | 0 | 1 | 1 | 0 | 0 |
| 2014-02-12 | 0 | 1 | 0 | 0 | 0 | 0 | 0 |
| 2014-02-13 | 0 | 0 | 0 | 0 | 1 | 0 | 1 |
| 2014-02-14 | 1 | 0 | 0 | 1 | 9 | 0 | 0 |
Try this:
select Date,
sum(case when diff <= -3 then 1 else 0 ) AS [<=-3],
sum(case when diff = -2 then 1 else 0 ) AS [-2],
sum(case when diff = -1 then 1 else 0 ) AS [-1],
sum(case when diff = 0 then 1 else 0 ) AS [0],
sum(case when diff = 1 then 1 else 0 ) AS [+1],
sum(case when diff = 2 then 1 else 0 ) AS [+2],
sum(case when diff >= 3 then 1 else 0 ) AS [>=+3]
from
(select Date, Num1, Num2, (Num1-Num2) diff from TableA)TableB
group by Date
I need help with a SQL that will convert this table:
===================
| Id | FK | Status|
===================
| 1 | A | 100 |
| 2 | A | 101 |
| 3 | B | 100 |
| 4 | B | 101 |
| 5 | C | 100 |
| 6 | C | 101 |
| 7 | A | 102 |
| 8 | A | 102 |
| 9 | B | 102 |
| 10 | B | 102 |
===================
to this:
==========================================
| FK | Count 100 | Count 101 | Count 102 |
==========================================
| A | 1 | 1 | 2 |
| B | 1 | 1 | 2 |
| C | 1 | 1 | 0 |
==========================================
I can so simple counts, etc., but am struggling trying to pivot the table with the information derived. Any help is appreciated.
Use:
SELECT t.fk,
SUM(CASE WHEN t.status = 100 THEN 1 ELSE 0 END) AS count_100,
SUM(CASE WHEN t.status = 101 THEN 1 ELSE 0 END) AS count_101,
SUM(CASE WHEN t.status = 102 THEN 1 ELSE 0 END) AS count_102
FROM TABLE t
GROUP BY t.fk
use:
select * from
(select fk,fk as fk1,statusFK from #t
) as t
pivot
(COUNT(fk1) for statusFK IN ([100],[101],[102])
) AS pt
Just adding a shortcut to #OMG's answer.
You can eliminate CASE statement:
SELECT t.fk,
SUM(t.status = 100) AS count_100,
SUM(t.status = 101) AS count_101,
SUM(t.status = 102) AS count_102
FROM TABLE t
GROUP BY t.fk