Data Table Sum Issue - asp.net

I have a situation.
I have datatable that contains the Credit and Debit columns like this
Month Credit Debit
Sep 1422825 0
Oct 0 1422825
Oct 1695017.5 0
Nov 0 1400000
Nov 0 295018
I want a balance that should be shown like this
Month Credit Debit Balance
Sep 1422825 0
Oct 0 1422825 (1422825 of Credit-1422825 of Debit)=0
Oct 1695017.5 0
Nov 0 1400000
Nov 0 295018 (1695017.5 of credit-1400000+295018)=0.5
it should be shown on crystal report how to do it.

Here's your solution optimized for 2005, I'm sure it works well on 2008.
(use integer for month, it's easier...)
DECLARE #Temp TABLE (Month int, Credit money, Debit money, Balance money)
DECLARE #RunningTotal money
SET #RunningTotal = 0
INSERT INTO #Temp
SELECT Month, Credit, Debit, null
FROM Datatable
ORDER BY Month
UPDATE #Temp
SET #RunningTotal = Balance = #RunningTotal + Credit - Debit
FROM #Temp
SELECT * FROM #Temp
EDIT (this continues from first step):
If you need to display total only last record in group (month) then you can use ranking function, like...
;WITH Temp2 AS
(
SELECT
*,
ROW_NUMBER() OVER (
PARTITION BY Month
ORDER BY Credit DESC, Debit DESC -- whatever order inside group you need
) AS N
FROM #Temp
)
SELECT
Month,
Credit,
Debit,
Balance = CASE WHEN N = 1 THEN Balance ELSE NULL END
FROM Temp2
This is not tested, code written directly from my head :P

Related

Get the MAX(value) using fiscal type years ie; 2016/2017, etc

My calendar year runs from 07-01-(of one year) to 06-30-(of the next year).
My SQLITE DB has a Timestamp column and it's data type is datetime and stores the timestamp as 2023-09-01 00:00:00.
What I'm trying to do is get the MAX date of the latest snowfall. For example, with my seasonal years beginning July-01 (earliest) and ending June 30 (latest), I want to find only the latest (MAX) date snowfall was recorded, regardless of the year, based on the month.
Say if out of five years (2017 to 2022) worth of data in the database and it snowed Mar 15, 2020. And there was no date greater than than this one in any year, then this would be the latest date regardless which year it fell.
I've been trying many variations of the below query. This query says it runs with no mistakes and returns "null" values. I'm using SQLITE DB Browser to write and test the query.
SELECT Timestamp, MAX(strftime('%m-%d-%Y', Timestamp)) AS lastDate,
snowDepth AS lastDepth FROM DiaryData
WHERE lastDepth <> 0 BETWEEN strftime('%Y-%m-%d', Timestamp,'start of year', '+7 months')
AND strftime('%Y-%m-%d', Timestamp, 'start of year', '+1 year', '+7 months', '- 1 day')
ORDER BY lastDate LIMIT 1
and this is what's in my test database:
Timestamp snowFalling snowLaying snowDepth
2021-11-10 00:00:00 0 0 7.2
2022-09-15 00:00:00 0 0 9.5
2022-12-01 00:00:00 1 0 2.15
2022-10-13 00:00:00 1 0 0.0
2022-05-19 00:00:00 0 0 8.82
2023-01-11 00:00:00 0 0 3.77
If it's running properly I should expect:
Timestamp
lastDate
lastDepth
2022-05-19 00:00:00
05-19-2022
8.82
What am I missing or is this not possible in SQLITE? Any help would be appreciative.
Use aggregation by fiscal year utilizing SQLite's feature of bare columns:
SELECT Timestamp,
strftime('%m-%d-%Y', MAX(Timestamp)) AS lastDate,
snowDepth AS lastDepth
FROM DiaryData
WHERE snowDepth <> 0
GROUP BY strftime('%Y', Timestamp, '+6 months');
See the demo.
I'd get season for each record first, snowfall date relative to record's season start date after this, and largest snowfall date relative to record's season start date finally:
with
data as (
select
*
, case
when cast(strftime('%m', "Timestamp") as int) <= 7
then strftime('%Y-%m-%d', "Timestamp", 'start of year', '-1 year', '+6 months')
else strftime('%Y-%m-%d', "Timestamp", 'start of year', '+6 months')
end as "Season start date"
from DiaryData
where 1==1
and "snowDepth" <> 0.0
)
, data2 as (
select
*
, julianday("Timestamp") - julianday("Season start date")
as "Showfall date relative to season start date"
from data
)
, data3 as (
select
"Timestamp"
, "snowFalling"
, "snowLaying"
, "snowDepth"
from data2
group by null
having max("Showfall date relative to season start date")
)
select
*
from data3
demo
You can use the ROW_NUMBER window function to address this problem, yet need to apply a subtle tweak. In order to account for fiscal years, you can partition on the year for timestamps slided 6 months further. In this way, ranges like [2021-01-01, 2021-12-31] will instead be slided to [2021-06-01, 2022-05-31].
WITH cte AS (
SELECT *, ROW_NUMBER() OVER(
PARTITION BY STRFTIME('%Y', DATE(Timestamp_, '+6 months'))
ORDER BY Timestamp_ DESC ) AS rn
FROM tab
)
SELECT Timestamp_,
STRFTIME('%d-%m-%Y', Timestamp_) AS lastDate,
snowDepth AS lastDepth
FROM cte
WHERE rn = 1
Check the demo here.

Window function lag() in trigger uses default instead of previous value

I'm trying to create an SQLite trigger to update balance for a particular account code.
accounts table :
CREATE TABLE accounts (
year INTEGER NOT NULL,
month INTEGER NOT NULL CHECK(month BETWEEN 1 AND 12),
amount REAL NOT NULL CHECK(amount >= 0),
balance REAL,
code INTEGER NOT NULL
);
When a new row is inserted I want the balance value of the new row to reflect OLD balance + NEW amount. But this trigger does not recognize the lagging balance value and I cannot figure out why:
CREATE TRIGGER trg_accounts_balance
AFTER INSERT ON accounts
BEGIN
UPDATE accounts
SET balance = (
SELECT
lag(balance, 1, 0) OVER (
PARTITION BY code
ORDER BY month
) + NEW.amount
FROM accounts
)
WHERE rowid = NEW.ROWID;
END;
If I insert one row per month, I expect my data to look like:
year
month
amount
balance
code
2022
1
100.0
100.0
100
2022
2
9.99
109.99
100
But I get:
year
month
amount
balance
code
2022
1
100.0
100.0
100
2022
2
9.99
9.99
100
What am I doing wrong?
The query:
SELECT
lag(balance, 1, 0) OVER (
PARTITION BY code
ORDER BY month
)
FROM accounts
returns as many rows as there are in the table and SQLite picks the first (whichever it is) to return it as the result so that it can use it to add NEW.amount.
There is nothing that links this value to the specific row that was inserted.
Instead, use this:
CREATE TRIGGER trg_accounts_balance
AFTER INSERT ON accounts
BEGIN
UPDATE accounts
SET balance = COALESCE(
(
SELECT balance
FROM accounts
WHERE code = NEW.code
ORDER BY year DESC, month DESC
LIMIT 1, 1
), 0) + NEW.amount
WHERE rowid = NEW.ROWID;
END;
The subquery returns the previous inserted row by ordering the rows of the specific code descending and skipping the top row (which is the new row).
See the demo.

SQL Calculation for ASP.NET

In my SQL database I have a column that contains a fiscal year value. Fiscal Year start from Oct 1st to Sept 30th of the following year. For example the current fiscal year is 2011-2012 or "2011". I need a calculation to pull dates from my database.
I have a column in my table that contains dates (i.e. 05/04/2012), I need a calculation that will pull the dates for the selected fiscal year? So when I need to see the data for the date 02/14/2003, then I would need the fiscal year of 2002.
This all ties into my ASP.NET page, where a user selects which fiscal year they want to view and a gridview appears with the information requested. So, if I choose fiscal year 2010, the data pulled into the gridview should be all records from 10/01/2010 to 09/30/2011. Thanks for the help, I have yet to try anything because I am not sure where to begin (sql newbie).
You can find the fiscal year by adding three months:
year(dateadd(month,3,'2011-09-30'))
So to select all entries in Fiscal year 2011, try:
select *
from YourTable as yt
where year(dateadd(month,3,yt.TransactionDt)) = 2011
I assume you are using SqlParameters to send data to the SQL Server. Then:
int fiscal_year = 2002;
SqlParameter fyStart = new SqlParameter("#FiscalYearStart",
SqlDbType.DateTime);
fyStart.Value = new SqlDateTime(fiscalYear, 10, 01);
SqlParameter fyEnd = new SqlParameter("#FiscalYearEnd",
SqlDbType.DateTime);
fyEnd.Value = new SqlDateTime(fiscalYear+1, 10, 01);
Then you can pass these two params to an Stored Procedure for example, and to query the table with
WHERE date BETWEEN #FiscalYearStart AND #FiscalYearEnd
N.B. FiscalYearEnd should be 10-Oct-YEAR+1, as it will be represented as YYYY-10-01T00:00:00, or will include the whole 30 Sept.
You could query for it:
SELECT *
FROM YourTable
WHERE YourTableDate >= CAST(#FiscalYear AS CHAR(4)) + '-10-01'
AND YourTableDate < CAST(#FiscalYear + 1 AS CHAR(4)) + '-10-01';
or, if you need the flexibility, you could alternatively have a table of date ranges which join to fiscal years. This gives you the ability to have multiple fiscal year definitions for, say, multiple tenants or companies, or allows the definition to change without changing your queries. You could then join to this table as needed to filter your results.
CompanyID FiscalYear StartDate EndDate
1 2010 2010-10-01 2011-09-30
1 2011 2011-10-01 2012-09-30
2 2010 2010-01-01 2011-12-31
2 2011 2011-01-01 2012-12-31
SELECT *
FROM YourTable t
INNER JOIN FiscalYear y
ON y.FiscalYear = t.FiscalYear
WHERE t.YourTableDate >= y.StartDate AND t.YourTableDate < DATEADD(d, 1, y.EndDate);

how to show sum(cost) and revenue from two tables and display per month

i have two tables:
table 1:
Expense cost
Posting Date
table 2:
Employee cost
Rvenue
Billing Date
Totalcost = Expense cost + Employee cost
Pofit Revenue - TotalCost
i have to display the report like so. It should show data per month according to year lets say 2011, (i know how to filter by year)
Totalcost | Revenue | Profit
jan
feb
mar
apr
may
jun
jul
aug
sep
oct
nov
dec
I'm having a tough time fugring out the query.
The problem is how can i display the data in report viewer table
Simplest way would be to combine the data to form a single data-table that will act as a data-source for the report.
You can join both tables at database side - for example,
SELECT
t1.Month,
t1.ExpenseCost + t2.EmployeeCost AS TotalCost,
t2.Revenue,
t2.Revenue - t1.ExpenseCost - t2.EmployeeCost AS Profit
FROM
Table1 t1
INNER JOIN Table2 t2 ON t1.Year = t2.Year and t1.Month = t2.Month
WHERE
t1.Year = #Year /* parameter to filter for a year */
or you can combine the data at front end either by using data relation or more simply by using LINQ over data tables - for example
var query = from t1 in table1.AsEnumerable()
join t1 in table2.AsEnumerable()
on t1.Field<string>("Month") equals t2.Field<string>("Month")
select new
{
Month = t1.Field<string>("Month"),
TotalCost = t1.Field<Decimal>("ExpenseCost") + t2.Field<Decimal>("EmployeeCost"),
Revenue = t2.Field<Decimal>("Revenue"),
// similarly compute profit
};

SQL Group Distinct Count

I have the following table
User ID Start Date End Date
-------------------------------------
John Doe Mar 11 2011 May 28 2011
Robret S Mar 21 2011 Jun 29 2011
Tina T Feb 01 2011 August 20 2011
I want to show how many people I have available for the past 6 months, even if the month has no people. How can this be possible. I know I have to do grouping and use distinct count.
Expected Output:
February = 1 Resource
March = 3 Resources
April = 3 Resources
May = 3 Resources
June = 2 Resources
July = 1 Resource
August = 1 Resource
With Calendar As
(
Select Cast('20110501' As DateTime) As [Date]
Union All
Select DateAdd(m,-1,[Date])
From Calendar
Where [Date] > DateAdd(m,-5,'20110501')
)
Select DateName(m, C.Date) + ' ' + Cast(Year(C.Date) As char(4))
, Case Count(*)
When 1 Then Cast(Count(*) As varchar(10)) + ' Resource'
Else Cast(Count(*) As varchar(10)) + ' Resources'
End
From Calendar As C
Left Join MyTable As T
On C.Date Between T.StartDate And T.EndDate
Group By C.Date
Results:
December 2010 | 1 Resource
January 2011 | 1 Resource
February 2011 | 1 Resource
March 2011 | 1 Resource
April 2011 | 3 Resources
May 2011 | 3 Resources
You will need the existing data records for the last 6 months, so that you can merge the two sets of data. You can generate the last 6 months in a CTE and do a left join with your data. That will allow you to show the last 6 months even if you have no data.
I don't think you can do what you want using a "simple" select statement (even using GROUPing etc.) The following is off the top of my head, so you'll have to experiment with it a little, and preferably read Joe Celko's excellent SQL for Smarties book.
You need to create a second table that contains all of your months (start/end dates). You only need one table for all types of similar queries, and it must contain all the months in the date ranges your interested in querying:
CREATE TABLE months (id, start DATE, end DATE);
INSERT INTO months (id, start, end)
values ( (1, 2011-01-01, 2011-01-31),
(2, 2011-02-01, 2011-02-28), ...);
You then LEFT OUTER JOIN from your user table to this month table. That will give you a row for each user for each month they were available, which you can GROUP as required:
SELECT months.id, COUNT(user.id)
FROM months LEFT OUTER JOIN users
ON user.start_date < months.end
AND user.end_date > months.start
GROUP BY months.id;
Hope that helps.
WITH resources AS (
SELECT
Date = DATEADD(month, v.number, [Start Date])
FROM atable t
INNER JOIN master.dbo.spt_values v ON v.type = 'P'
AND v.number BETWEEN 0 AND DATEDIFF(month, t.[Start Date], t.[End Date])
)
SELECT
Month = DATENAME(month, Date),
ResourceCount = CAST(COUNT(*) AS varchar(30)) +
CASE COUNT(*) WHEN 1 THEN ' Resource' ELSE ' Resources' END
FROM resources
WHERE Date > DATEADD(month, -6, DATEADD(day, -DAY(GETDATE()), GETDATE()))
GROUP BY YEAR(Date), MONTH(Date), DATENAME(month, Date)
ORDER BY YEAR(Date), MONTH(Date)

Resources