Summing Counts into Multiple New Columns Grouped By Another Column - sql

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

Related

SQL - Need return from single table of SUMs over 3 different date ranges

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.

How to set value based on value existence in SQL Server?

I have the following T-SQL code:
select
id,
(case
when n in(Bla1', 'Bla2') then 1
when n = 'Bla3' then 99
else 0
end) as c
from
hello
Running this code outputs this result:
| id | c |
+--------+----+
| 577140 | 0 |
| 577140 | 1 |
| 577140 | 0 |
| 577140 | 0 |
| 577140 | 99 |
| 577141 | 0 |
| 577141 | 0 |
| 577141 | 0 |
| 577142 | 0 |
| 577142 | 0 |
| 577142 | 1 |
How can I modify the code to get the following output?
| id | c |
+--------+----+
| 577140 | 99 |
| 577141 | 0 |
| 577142 | 1 |
Rule
For each id: If 99 exists, then c becomes 99. If not, either 1 or 0, depending if any 1 exists.
You can use aggregation:
select id,
max(case when n in ('Bla1', 'Bla2') then 1
when n = 'Bla3' then 99
else 0
end) as c
from hello
group by id;

SQL pivot to arrange data to 12 months output

I have a Table named: ListOfdates
TYPE | O_DATE | C_DATE |
+------+-------------+---------------+
A 15-JAN-2017 (NULL)
A 15-JAN-2017 (NULL)
A 15-JAN-2017 25-APR-2017
A 15-JAN-2017 (NULL)
A 24-FEB-2017 (NULL)
A 15-MAY-2017 (NULL)
B 15-MAY-2017 25-MAY-2017
C 15-MAY-2017 (NULL)
D 15-MAY-2017 26-MAY-2017
A 15-MAY-2017 (NULL)`
I want to arrange it into the below,
`MONTH | Type A |Total| Type B |Total| Type C |Total| Type D |Total|
| A_o | A_c | T_o | B_o | B_c | T_o | C_o | C_c | T_o | D_o | D_c | T_o |
JAN | 4 | 0 | 4 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
FEB | 1 | 0 | 5 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
MAR | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
APR | 0 | 1 | 4 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
MAY | 2 | 0 | 6 | 1 | 0 | 0 | 1 | 0 | 0 | 0 | 1 | 0 |
JUN | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
...`
The conditions are,
o_date will add a count to open for the month and type.
If c_date is not null, it will add a count to the close for the month and type
else if it is null for the c_date, there won't be a count to the close.
also, there will be a total count for the number of open for each type accumulated from the start of the year.
All 12 months must be displayed.
The acronym are:
`O_DATE = open date
C_DATE = close date
A_o = Type A open
A_c = Type A close
B_o = Type A open
B_c = Type B close
C_o = Type C open
T_o = Total open for the type (example may have 2 type A that is open)
etc...`
Is there a way to do it in sql with pivot?
I would do this using conditional aggregation, but first you have to unpivot the data:
select to_char(dte, 'MON'),
sum(case when type = 'A' then open else 0 end) as A_o,
sum(case when type = 'A' then close else 0 end) as A_c,
sum(case when type = 'A' then 1 else 0 end) as A_total,
. . .
from ((select type, o_date as dte, 1 as open, 0 as close from t) union al
(select type, c_date as dte, 0 as open, 1 as close from t)
) oc
group by to_char(dte, 'MON')
order by min(dte);

SQL - Add Column With Count()

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)

SSRS Remove Column from Report

i am including column 13 as a dummy column here:
+----+---+---+---+----+---+---+---+---+---+----+----+----+----+
| | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 |
+----+---+---+---+----+---+---+---+---+---+----+----+----+----+
| 1 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 1 |
| 2 | 0 | 0 | 1 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 1 |
| 3 | 0 | 0 | 0 | 0 | 0 | 1 | 0 | 0 | 0 | 0 | 0 | 0 | 1 |
| 4 | 1 | 0 | 0 | 20 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 1 |
| 5 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 1 |
| 6 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 1 |
| 7 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 1 |
| 8 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 1 |
| 9 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 1 |
| 10 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 1 |
+----+---+---+---+----+---+---+---+---+---+----+----+----+----+
the reason i am including a dummy column is so that IF columns 1 through 12 are all zero, i would still like to include an entry for that row.
as you can see row 1 would not have been included.
this report is generated by SSRS.
i am wondering if there is a way to HIDE column 13?
is there some kind of conditional formatting i can do?
to clarify here's my query:
select tat.*, tat.tat as tat2 from tat
it is organized in the report this way:
this data set [TAT] contains dummy data specifically for column 13
Specific columns in a column group can be hidden based on values with the following steps.
Right-click header of the column group you want to hide, Column Group -> Group Properties
Click on the Visibility pane and select Show or hide based on an expression radio button. Use an expression to determine when column is hidden.
True hides the column, False displays it. You will need to update the field name in my example to match your month field name.
Don't include column 13 in your select? If you are doing a select *, change it to Select col1, col2, ...., col12