How to drop a field from a running count - sql

I am tasked with trying to come up with a total count for the number of clients we have had in any given year. I am able to run a total count of the clients we have had, but I want to drop them from the running total when they offboard from us (i.e. #EndDate)
DECLARE #EndDate Date
SET #EndDate = (SELECT DISTINCT LOAEndDate FROM tblCompany)
SELECT DISTINCT Year(DateBecameClient) AS [Year],
Count(CompanyId) OVER (ORDER BY Year(DateBecameClient)) AS NumberofClients
FROM [tblCompany] AS Company
ORDER BY [Year]
Here is the output that I get without including #EndDate.
--------------------
Year NumberofClients
2001 3
2002 6
2003 9
2004 10
2005 13
2006 15
2007 16
2008 26
2009 36
2010 78
2011 135
2012 204
2013 314
2014 385
2015 456
2016 471
2017 496
2018 507
2019 513
2020 514
2021 516

I presume that you have a separate date that indicates when the client left. You'll want to counterbalance with a -1 via a union. If a client was added and lost within the same year it'll never be counted:
with data as (
select year(DateBecameClient) as yr, 1 as num
from tblCompany
union all
select year(DateLostClient), -1
from tblCompany
)
select yr as "Year", sum(sum(num)) over (order by yr) as NumberOfClients
from data
group by yr
order by "Year";
I'm using grouping with a sum of sums to get around needing distinct. This is basically the same as your query except for the addition of the negative counters.

Related

SQL Count with rollup shows totals as NULL

I need to know how I can replace the NULL with total.
Here is a copy of my query using ROLLUP.
SELECT DATEPART(YEAR, study_date) AS 'Year',
COUNT(distinct study_uid) AS 'Studies'
FROM local_studies
GROUP BY rollup (DATEPART(YEAR, study_date))
ORDER BY 'Year' DESC
This is the output:
Year Studies
2020 497
2019 165743
2018 165043
2017 182712
2016 210700
2015 219373
2014 214097
2013 211566
2012 212900
2011 217957
2010 213542
2009 193510
2008 95434
2007 53722
2006 44422
2005 12119
2004 129
2003 65
2000 4
NULL 2413535
I like to see the 'NULL" value replace with 'Total': (as shown below)
Year Studies
2020 497
2019 165743
2018 165043
2017 182712
2016 210700
2015 219373
2014 214097
2013 211566
2012 212900
2011 217957
2010 213542
2009 193510
2008 95434
2007 53722
2006 44422
2005 12119
2004 129
2003 65
2000 4
Total 2413535
Any advice for converting that NULL to the word TOTAL would be greatly appreciated.
I usually just use coalesce():
SELECT COALESCE(DATENAME(YEAR, study_date), 'Total') AS Year,
COUNT(distinct study_uid) AS 'Studies'
FROM local_studies
GROUP BY rollup (DATENAME(YEAR, study_date))
ORDER BY Year DESC;
Note that this switches to using DATENAME() so the column is a string and not a number.
Also, this doesn't work so well if the value could be NULL. For that, there is the GROUPING() function.
SELECT CASE GROUPING_ID(DATEPART(YEAR, study_date)) WHEN 1 THEN 'Total' ELSE CAST(DATEPART(YEAR, study_date) AS VARCHAR(10)) END AS 'Year',
COUNT(distinct study_uid) AS 'Studies'
FROM local_studies
GROUP BY rollup (DATEPART(YEAR, study_date))
ORDER BY GROUPING_ID(DATEPART(YEAR, study_date)), 'Year' DESC;

Percent of change by year and month

I have code that distinctly counts authorizations grouped by month and year.
I added a calculated field to show the percent of change but my issue is I only want to get this percentage between the years by month.
My code calculates the percent for each previous row. which when pulled into SSRS displays the incorrect value after the for column.
Select D.Month
,D.Year
,count( distinct D.authorization_number) [Admission Events]
,CAST(lag(Count(distinct D.authorization_number), 1) over (order by D.month) - Count(distinct D.authorization_number) as FLOAT) / CAST(Count(distinct D.authorization_number)as FLOAT) [Admission Events Pct]
From #Detail D
Group BY D.Month
,D.Year
In these results I would like to only display the pct for year 2018 in SSRS.
Month Year Admission Events Admission Events Pct
1 2017 5919 NULL
1 2018 6057 -0.0227835562159485
2 2017 5302 0.142399094681252
2 2018 5234 0.0129919755445166
3 2017 5548 -0.0565969718817592
3 2018 5389 0.0295045462980145
4 2017 5128 0.0508970358814353
4 2018 5503 -0.0681446483736144
5 2017 5768 -0.0459431345353675
5 2018 5708 0.0105115627189909
6 2017 5461 0.0452298113898553
6 2018 2606 1.09554873369148
Is this what you want?
select t.*
from (<your query here>) t
where year = 2018;
You need a subquery or CTE so the where doesn't interfere with the lag().

Getting Monthly Data

I want to extract all budget entries charged to the current year and cumulated over each month after .In January, taking the total over January, February take accumulated of January plus accumulated February...
I started with this query :
IF OBJECT_ID('tempdb..#BudgetTransTmp') IS NOT NULL
DROP TABLE #BudgetTransTmp
Select
Row_number() over(ORDER BY YEAR(BTLine.DATE),MONTH(BTLine.DATE)) as RowNumber,
COMBINATION.DISPLAYVALUE,
BTLine.LedgerDimension AS LedgerDimension,
MIN(BTLine.TransactionCurrencyAmount) AS Amount,
SUM(BTLine.TransactionCurrencyAmount)
OVER (ORDER BY YEAR(BTLine.DATE),MONTH(BTLine.DATE),BTLine.LedgerDimension,COMBINATION.DISPLAYVALUE ) AS SUM,
YEAR(BTLine.DATE) AS Year ,
MONTH(BTLine.DATE) AS MONTH
INTO #BudgetTransTmp
FROM MicrosoftDynamicsAX.dbo.BudgetTransactionLine AS BTLine
--Get Display value
INNER JOIN MicrosoftDynamicsAX.dbo.DIMENSIONATTRIBUTEVALUECOMBINATION AS COMBINATION
ON COMBINATION.RECID = BTLine.LEDGERDIMENSION
GROUP BY
BTLine.LedgerDimension,
YEAR(BTLine.DATE),
MONTH(BTLine.DATE)
ORDER BY RowNumber
The result is :
LedgerDimension Amount SUM Year Month Display
1 22565448266 850.00 850.00 2012 8 601200-001-027--
2 22565448265 1700.00 2550.0 2012 12 601200-002-027--
3 22565448266 2700.00 5250.00 2012 12 601200-001-027--
4 22565448267 650.00 5900.00 2012 12 601400-002-027--
5 22565448268 1100.00 7000.00 2012 12 601400-001-027--
But i want to get
LedgerDimension Amount SUM Year Month Display
1 22565448266 850.00 850.00 2012 8 601200-001-027--
2 22565448265 1700.00 1700.0 2012 12 601200-002-027--
3 22565448266 2700.00 3350.00 2012 12 601200-001-027--
4 22565448267 650.00 650.00 2012 12 601400-002-027--
5 22565448268 1100.00 1100.00 2012 12 601400-001-027--
I think my COMBINATION of ORDER by (primary key) must be betwwen LedgerDimension ,Year , Month , Display
Any help in this regards
I think what you need to do is:
SUM(BTLine.TransactionCurrencyAmount)
OVER (PARTITION BY BTLine.LedgerDimension ORDER BY YEAR(BTLine.DATE),MONTH(BTLine.DATE),BTLine.LedgerDimension,COMBINATION.DISPLAYVALUE ) AS SUM
let me know if this works.

SQL Nested Multiple Select Statement

Im trying to create a nested SQL statement with multiple Nested Select Statements, to be used on a record set import in excel vba.
What i want to do is create something like:
SELECT
N.LimitN,
Sum(N.amountN),
Sum(N1.amountN1)
FROM (
SELECT year as yearN, Sum(amount) as amountN, limit as limitN
FROM table1
WHERE year = 2013
GROUP BY year, limit) as N
JOIN (
SELECT year as yearN1, Sum(amount) as amountN1, limit as limitN1
FROM table1
WHERE year = 2014
GROUP BY year, limit) as N1
ON N.LimitN = N1.LimitN1
GROUP BY N.LimitN
ORDER BY N.LimitN;
So that if my Raw data is like this:
Year Amount Limit
2013 100 20
2013 90 30
2013 120 40
2013 5 20
2013 100 30
2013 105 40
2013 150 50
2014 115 20
2014 50 30
2014 95 40
2014 110 50
2014 30 20
My Resulting Table/record set will be like this:
Limit AmountN (i.e. 2013) Amount N1 (i.e. 2014)
20 105 145
30 190 50
40 225 95
50 150 110
Thanks in Advance
Peter
It feels like you're overcomplicating the query a little, what you want is just a year wise sum of amount, grouped by limit. This can be done using a CASE;
SELECT
limit,
SUM(CASE WHEN year=2013 THEN amount ELSE 0 END) amountN,
SUM(CASE WHEN year=2014 THEN amount ELSE 0 END) amountN1
FROM myTable
GROUP BY limit
ORDER BY limit;
An SQLfiddle to test with.
(if we're talking Access here, you will need to use IIF instead of CASE)

Generate year to date by month report in SQL [duplicate]

This question already has answers here:
Closed 11 years ago.
Possible Duplicate:
Running total by grouped records in table
I am trying to put together an SQL statement that returns the SUM of a value by month, but on a year to date basis. In other words, for the month of March, I am looking to get the sum of a value for the months of January, February, and March.
I can easily do a group by to get a total for each month by itself, and potentially calculate the year to date value I need in my application from this data by looping through the results set. However, I was hoping to have some of this work handled with my SQL statement.
Has anyone ever tackled this type of problem with an SQL statement, and if so, what is the trick that I am missing?
My current sql statement for monthly data is similar to the following:
Select month, year, sum(value) from mytable group by month, year
If I include a where clause on the month, and only group by the year, I can get the result for a single month that I am looking for:
select year, sum(value) from mytable where month <= selectedMonth group by year
However, this requires me to have a particular month pre-selected or to utilize 12 different SQL statements to generate one clean result set.
Any guidance that can be provided would be greatly appreciated!
Update: The data is stored on an IBM iSeries.
declare #Q as table
(
mmonth INT,
value int
)
insert into #Q
values
(1,10),
(1,12),
(2,45),
(3,23)
select sum(January) as UpToJanuary,
sum(February)as UpToFebruary,
sum(March) as UpToMarch from (
select
case when mmonth<=1 then sum(value) end as [January] ,
case when mmonth<=2 then sum(value) end as [February],
case when mmonth<=3 then sum(value) end as [March]
from #Q
group by mmonth
) t
Produces:
UpToJanuary UpToFebruary UpToMarch
22 67 90
You get the idea, right?
NOTE: This could be done easier with PIVOT tables but I don't know if you are using SQL Server or not.
As far as I know DB2 does support windowing functions although I don't know if this is also supported on the iSeries version.
If windowing functions are supported (I believe IBM calls them OLAP functions) then the following should return what you want (provided I understood your question correctly)
select month,
year,
value,
sum(value) over (partition by year order by month asc) as sum_to_date
from mytable
order by year, month
create table mon
(
[y] int not null,
[m] int not null,
[value] int not null,
primary key (y,m))
select a.y, a.m, a.value, sum(b.value)
from mon a, mon b
where a.y = b.y and a.m >= b.m
group by a.y, a.m, a.value
2011 1 120 120
2011 2 130 250
2011 3 500 750
2011 4 10 760
2011 5 140 900
2011 6 100 1000
2011 7 110 1110
2011 8 90 1200
2011 9 70 1270
2011 10 150 1420
2011 11 170 1590
2011 12 600 2190
You should try to join the table to itself by month-behind-a-month condition and generate a synthetic month-group code to group by as follows:
select
sum(value),
year,
up_to_month
from (
select a.value,
a.year,
b.month as up_to_month
from table as a join table as b on a.year = b.year and b.month => a.month
)
group by up_to_month, year
gives that:
db2 => select * from my.rep
VALUE YEAR MONTH
----------- ----------- -----------
100 2011 1
200 2011 2
300 2011 3
400 2011 4
db2 -t -f rep.sql
1 YEAR UP_TO_MONTH
----------- ----------- -----------
100 2011 1
300 2011 2
600 2011 3
1000 2011 4