Displaying different date periods on income data - sql

I have the below query which displays data like so:
Income Type This Month Last Month This Year Last Year
1 179640.00 179640.00 179640.00 179640.00
2 12424440.00 12424440.00 12424440.00 12424440.00
Select
Income_Type As [Income Type],
Sum(Income_Amount) As [This Month],
Sum(Income_Amount) As [Last Month],
Sum(Income_Amount) As [This Year],
Sum(Income_Amount) As [Last Year]
From Income I
Left Join Finance_Types FT On I.Income_Type = FT.Type_ID
Group By
Income_Type
The Income table has a Income_Date which is a datetime column.
I'm struggling to get my head around how I would pull out the data for 'This Month', 'Last Month', 'This Year', 'Last Year' with the correct Sums in one query if possible?

Use date functions:
SUM(CASE WHEN YEAR(yourdatefield) = YEAR(GetDate()) - 1 THEN Income_Amount ELSE 0 END) AS 'Last Year'
That case statement only returns the Income_Amount if it was the last year, so you would be summing up only those amounts.
If you're not using SQL Server, the syntax might be a bit different.

Related

SQL create column for every week (Loop?)

I need to make a report for weekly changes.
This is the code for todays amount
SELECT
[Entry No_],
[Customer No_],
[Posting Date],
[Description],
[Currency Code],
Trans_type = case when [Deposit]=1 then 'Deposit'
when [Imprest]=1 then 'Imprest'
else 'Other' end,
A.Amount
FROM Table1
LEFT JOIN
(
SELECT Distinct [Cust_ Ledger Entry No_],
SUM ([Amount EUR]) as 'amount'
FROM Table2
group by [Cust_ Ledger Entry No_]
having
SUM ([Amount EUR]) <> '0'
)A
on [Entry No_] = A.[Cust_ Ledger Entry No_]
Where
A.Amount is not NULL
Code to generate data for previous week is here (adding only where clause):
SELECT
[Entry No_],
[Customer No_],
[Posting Date],
[Description],
[Currency Code],
Trans_type = case when [Deposit]=1 then 'Deposit'
when [Imprest]=1 then 'Imprest'
else 'Other' end,
A.Amount
FROM Table1
LEFT JOIN
(
SELECT Distinct [Cust_ Ledger Entry No_],
SUM ([Amount EUR]) as 'amount'
FROM Table2
where [posting Date] < '2020-11-23'
group by [Cust_ Ledger Entry No_]
having
SUM ([Amount EUR]) <> '0'
)A
on [Entry No_] = A.[Cust_ Ledger Entry No_]
Where
A.Amount is not NULL
It would be enough to union both queries and then export to Excel and make pivot, but problem is that I need results of last 50 weeks. Is there any smart way to avoid union 50 tables and run one simple code to generate weekly report?
Thanks
it might be easier with sample, but I don't know how to paste table here..
Maybe it is true, i dont need union here, and group by would be enough, but it stills sounds difficult for me :)
Ok. Lets say table has such headers: Project | Country | date | amount
The code below returns amount for todays date
Select
Project,
SUM(amount)
From Table
Group by Project
I actually need todays date and also the results of previous weeks (What was the result on November 22 (week 47), November 15 (week 46) and so on.. total 50 weeks from todays date).
Code for previous week amount is here:
Select
Project,
SUM(amount)
From Table
Where Date < '2020.11.23'
Group by Project
So my idea was to create create 50 codes and join the results together, but i am sure it is a better way to do this. Besides i dont want to edit this query every week and add a new date for it.
So any ideas, to make my life easier?
if I have understood your requirement correctly, all you need to do is extract the week from the date e.g.
Select
Project,
datepart(week, date),
SUM(amount)
From Table
Where Date < '2020.11.23'
Group by Project, datepart(week, date)

How to select max date over the year function

I am trying to select the max date over the year, but it is not working. Any ideas on what to do?
SELECT a.tkinit [TK ID],
YEAR(a.tkeffdate) [Rate Year],
max(a.tkeffdate) [Max Date],
tkrt03 [Standard Rate]
FROM stageElite.dbo.timerate a
join stageElite.dbo.timekeep b ON b.tkinit = a.tkinit
WHERE a.tkinit = '02672'
and tkeffdate BETWEEN '2014-01-01' and '12-31-2014'
GROUP BY a.tkinit,
tkrt03,
a.tkeffdate
Perhaps you only want it by year and not rolled up by calendar date. For SQL server you can try this.
SELECT
…
MaxDate = MAX(a.tkeffdate) OVER (PARTITION BY a.tkinit, YEAR(a.tkeffdate)))
…
Or you could modify the query above to group by the year instead of date-->
GROUP BY a.tkinit,
tkrt03,
YEAR(a.tkeffdate)
You seem to want only one row and all the columns. Use ORDER BY and TOP:
SELECT TOP (1) tr.tkinit as [TK ID],
YEAR(tr.tkeffdate) as [Rate Year],
a.tkeffdate as [Max Date],
tkrt03 as [Standard Rate]
FROM stageElite.dbo.timerate tr JOIN
stageElite.dbo.timekeep tk
ON tk.tkinit = tr.tkinit
WHERE tr.tkinit = '02672' AND
tr.tkeffdate >= '2014-01-01' AND
tr.tkeffdate < '2015-01-01'
ORDER tr.tkeffdate DESC;
Note that I also fixed your date comparisons and table aliases.

New to SQL. Would like to convert an IF(COUNTIFS()) Excel formula to SQL code and have SQL calculate it instead of Excel

I am running SQL Server 2008 R2 (RTM).
I have a SQL query that pulls Dates, Products, Customers and Units:
select
[Transaction Date] as Date,
[SKU] as Product,
[Customer Name] as Customer,
sum(Qty) as Units
from dataset
where [Transaction Date] < '2019-03-01' and [Transaction Date] >= '2016-01-01'
group by [Transaction Date], [SKU], [Customer Name]
order by [Transaction Date]
This pulls hundreds of thousands of records and I wanted to determine if a certain transaction was a new order or reorder based on the following logic:
Reorder: That specific Customer has ordered that specific product in the last 6 months
New Order: That specific Customer hasn’t ordered that specific product in the last 6 months
For that I have this formula in Excel that seems to be working:
=IF(COUNTIFS(A$1:A1,">="&DATE(YEAR(A2),MONTH(A2)-6,DAY(A2)),C$1:C1,C2,B$1:B1,B2),"Reorder","New Order")
The formula works when I paste it individually or in a smaller dataset, but when I try to copy paste it to all 500K+ rows, Excel gives up because it loops for each calculation.
This could probably be done in SQL, but I don’t have the knowledge on how to convert this excel formula to SQL, I just started studying it.
You're doing pretty well with the start of your query there. There are three additional functions you're looking to add to your query.
The first thing you'll need is the easiest. GETDATE() simply returns the current date. You'll need that when you're comparing the current date to the transaction date.
The second function is DATEDIFF, which will give you a unit of time between two dates (months, days, years, quarters, etc). Using DATEDIFF, you can say "is this date within the last 6 months". The format for this is pretty easy. It's DATEDIFF(interval, date1, date2).
The thrid function you're looking for is CASE, which allows you to tell SQL to give you one answer if one condition is met, but a different answer if a different condition is met. For your example, you can say "if the difference in days is < 60, return 'Reorder', if not give me 'New Order'".
Putting it all together:
SELECT CASE
WHEN DATEDIFF(MONTH, [Transaction Date], GETDATE()) <= 6
THEN 'Reorder'
ELSE 'New Order'
END as ORDER_TYPE
,[Transaction Date] AS DATE
,[SKU] AS PRODUCT
,[Customer Name] AS CUSTOMER
,Qty AS UNITS
FROM DATASET
For additonal examples on CASE, take a look at this site: https://www.w3schools.com/sql/sql_ref_case.asp
For additional examples on DATEDIFF, take a look here: See the
following webpage for examples and a chance to try it out:
https://www.w3schools.com/sql/func_sqlserver_datediff.asp
SELECT CASE
WHEN Datediff(day, [transaction date], Getdate()) <= 180 THEN 'reorder'
ELSE 'Neworder'
END,
[transaction date] AS Date,
[sku] AS Product,
[customer name] AS Customer,
qty AS Units
FROM datase
If I understand correctly, you want to peak at the previous date and make a comparison. This suggests lag():
select (case when lag([Transaction Date]) over (partition by SKU, [Customer Name] order by [Transaction Date]) >
dateadd(month, -6, [Transaction Date])
then 'Reorder'
else 'New Order'
end) as Order_Type
[Transaction Date] as Date,
[SKU] as Product,
[Customer Name] as Customer,
sum(Qty) as Units
from dataset d
group by [Transaction Date], [SKU], [Customer Name];
EDIT:
In SQL Server 2008, you can emulate the LAG() using OUTER APPLY:
select (case when dprev.[Transaction Date] >
dateadd(month, -6, d.[Transaction Date])
then 'Reorder'
else 'New Order'
end) as Order_Type
d.[Transaction Date] as Date,
d.[SKU] as Product,
d.[Customer Name] as Customer,
sum(d.Qty) as Units
from dataset d outer apply
(select top (1) dprev.*
from dataset dprev
where dprev.SKU = d.SKU and
dprev.[Customer Name] = d.[Customer Name] and
dprev.[Transaction Date] < d.[Transaction Date]
order by dprev.[Transaction Date] desc
) dprev
group by d.[Transaction Date], d.[SKU], d.[Customer Name];

Getting percentages of counts in SQL Server

I am building an SQL Server query that gets the number of leads that were generated from a certain sources by month. This is the query that tells me the monthly count. But I want to add a column that shows what those leads are for that month as a total of all leads for that month. I'm not clear on how to do this. Any help?
SELECT FORMAT([ProspectData].[dbo].[Real Estate.KPC.Leads.2018-08-08].[Created Date]
, 'yyyy-MM') AS 'YYYY-MM'
, 'Kiosk-Mall' AS 'Lead Source'
, COUNT(*) AS 'Monthly Total From That Lead Source'
FROM [ProspectData].[dbo].[Real Estate.KPC.Leads.2018-08-08]
WHERE [ProspectData].[dbo].[Real Estate.KPC.Leads.2018-08-08].[Lead Source] =
'Kiosk-Mall'
GROUP BY FORMAT([ProspectData].[dbo].[Real Estate.KPC.Leads.2018-08-08].[Created Date], 'yyyy-MM')
ORDER BY FORMAT([ProspectData].[dbo].[Real Estate.KPC.Leads.2018-08-08].[Created Date], 'yyyy-MM');
You can use conditional aggregation -- basically moving the WHERE condition to a CASE expressions in the argument to an aggregation function:
SELECT FORMAT(l.[Created Date], 'yyyy-MM') AS YYYYMM,
'Kiosk-Mall' AS Lead_Source,
SUM(CASE WHEN l.[Lead Source] = 'Kiosk-Mall' THEN 1 ELSE 0 END) AS [Monthly Total From That Lead Source],
AVG(CASE WHEN l.[Lead Source] = 'Kiosk-Mall' THEN 1.0 ELSE 0 END) AS proportion_of_total
FROM [ProspectData].[dbo].[Real Estate.KPC.Leads.2018-08-08] l
GROUP BY FORMAT(l.[Created Date], 'yyyy-MM')
ORDER BY YYYYMM
Notes:
Table aliases make the query easier to write and to read.
It is better to choose column aliases that do not need to be escaped (i.e. no spaces, no punctuation).

Access SQL - Count days in each month between two dates

I have two tables - [Students] Which holds a list of students (and the name of their teacher), and [Absence Extract] Which holds a record of each instance of absence for any student (along with the start and end dates and total days).
I am trying to write a query that will group the days of absence by teacher and then show how many days of absence they have had in each month. I've started by writing the below query where I have shown the calculation I've come up with so far for days lost in January and February (I would then add the calculations for the other months), however this example isn't working as if they had e.g 15 days absence spread across January and February this is returning 15 days for both months.
Could someone point me in the right direction with this please?
SELECT
[Students].[Teacher Name] AS [Teacher],
SUM(IIF(ae.[Absence End Date] >= #1/1/18# AND ae.[Absence Start Date] <= #1/31/18#,[Total Days],0)) AS [Jan Days],
SUM(IIF(ae.[Absence End Date] >= #2/1/18# AND ae.[Absence Start Date] <= #2/28/18#,[Total Days],0)) AS [Feb Days]
FROM
[Students]
INNER JOIN
[Absence Extract] ae ON [Students].[ID] = [ae].[Student ID]
GROUP BY [Students].[Teacher Name];
Do not use the calculated column, Total Days, as it sums the difference between start and end dates across months and even years. Consider calculating separate durations:
absence duration from start date to end of start date month
absence duration from first of end date month to end date
Then join the aggregations together. So for example, the absence range Jan 30, 2018 - Feb 2, 2018:
first query calculates days from Jan 30 to Jan 31 (end of month), grouped to January month
second query calculates from Feb 1 (start of month) to Feb 2, grouped to February month
join query aligns to Teacher, Year, and Month, and calculates total duration with arithmetic addition, +, where 2 days result for Jan and 2 days result for Feb on different rows
Start Date Query
SELECT
s.[Teacher Name] AS [Teacher],
Year(ae.[Absence End Date]) As Year_Absence,
MonthName(Month(ae.[Absence Start Date]), TRUE) As Month_Absence,
SUM(DateDiff('d', ae.[Absence Start Date],
DateAdd('m', 1, ae.[Absence Start Date]) -
Day(ae.[Absence Start Date]))) As StartDuration
FROM
[Students] s
INNER JOIN
[Absence Extract] ae ON s[ID] = ae.[Student ID]
GROUP BY s.[Teacher Name],
Year(ae.[Absence Start Date])
MonthName(Month(ae.[Absence Start Date]), TRUE);
End Date Query
SELECT
s.[Teacher Name] AS [Teacher],
Year(ae.[Absence End Date]) As Year_Absence,
MonthName(Month(ae.[Absence End Date]), TRUE) As Month_Absence,
SUM(DateDiff('d', ae.[Absence End Date],
ae.[Absence End Date] -
(Day(ae.[Absence End Date])-1))) As EndDateDuration
FROM
[Students] s
INNER JOIN
[Absence Extract] ae ON s[ID] = ae.[Student ID]
GROUP BY s.[Teacher Name],
Year(ae.[Absence End Date])
MonthName(Month(ae.[Absence End Date]), TRUE);
Join Query (Long Format)
SELECT s.[Teacher Name],
s.Year_Absence,
s.Month_Absence,
NZ(s.StartDuration) + NZ(e.EndDateDuration) As TotalDuration
FROM startdate_query s
LEFT JOIN enddate_query e
ON s.[Teacher Name] = e.[Teacher Name]
AND s.Year_Absence = e.Year_Absence
AND s.Month_Absence = e.Month_Absence
And since you are looking for a wide report with month columns maintaining aggregate sums of absence duration, consider MS Access's own crosstab query.
Crosstab Query (Wide Format)
TRANSFORM SUM(NZ(s.StartDuration) + NZ(e.EndDateDuration)) AS [SumDays]
SELECT s.[Teacher Name],
s.Year_Absence
FROM startdate_query s
LEFT JOIN enddate_query e
ON s.[Teacher Name] = e.[Teacher Name]
AND s.Year_Absence = e.Year_Absence
AND s.Month_Absence = e.Month_Absence
GROUP BY s.[Teacher Name],
s.Year_Absence
PIVOT s.Month_Absence IN ('Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun',
'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec')
Of course, all this is untested without actual data. So, various adjustments may be needed.