How to compare two date values in SQL Server? - sql

I have a table with the date 2018 and date 2019 and here is my data.
select amount, date
from TABLE1
where date in (2018, 2019) and empid = 21120
It didn't work for me as the query says case when date =2019 then amount as my data above when date=2019 it will just show me the amount. This is what my result is:
Amount Data
9.67 2019
21 2019
6 2019
9.56 2018
42 2018
7 2018
What is want it: the difference between the Amount for the two dates 2018 and 2019.
The above query gives me only one row of the amount for those dates.
My expected result is to find the difference in the amount between 2018 and 2019. Any ideas on how I could get the difference. I am trying self joining but any help is appreciated.
Ex: 2019 amount 9.67 - 2018 amount 9.56.

You seem to be looking for conditional aggregation:
select
sum(case when date = 2019 then amount else 0 end)
- sum(case when date = 2018 then amount else 0 end) diff
from mytable
where empid = 21 and date in (2018, 2019)
The query gives you the difference between the total amount of 2019 and that of 2018 for the given employee.
This can be shortened a little:
select sum(case when date = 2019 then amount else -amount end) diff
from mytable
where empid = 21 and date in (2018, 2019)

You can do as
SELECT ABS(SUM(CASE WHEN Data = '2019' THEN Amount ELSE -Amount END)) Diff
FROM
(
VALUES
(9.67 , '2019'),
(21 , '2019'),
(6 , '2019'),
(9.56 , '2018'),
(42 , '2018'),
(7 , '2018')
) T(Amount, Data)
WHERE Data IN ('2018', '2019')
-- AND empid = 21120; Uncomment this when you run it against your table

Related

Teradata - Split date range into month columns with day count

I need to split different date ranges over a quarter period into month columns with only the days actually used in that month. Each record (range) would be different.
Example:
Table
Record_ID Start_Date End_Date
1 10/27 11/30
2 11/30 12/14
3 12/14 12/31
Range 1 = 10/5 to 12/14
Range 2 = 11/20 to 12/31
Range 3 = 10/28 to 12/2
Output:
Range 1
Oct Nov Dec
27 30 14
Similar to #ULick's answer using sys_calendar.calendar, but a little more succinct:
CREATE VOLATILE MULTISET TABLE datetest (record_id int, start_date date, end_date date) ON COMMIT PRESERVE ROWS;
INSERT INTO datetest VALUES (1, '2017-10-05', '2017-12-14');
INSERT INTO datetest VALUES (2, '2017-11-20','2017-12-31');
SELECT record_id,
SUM(CASE WHEN month_of_year = 10 THEN 1 ELSE 0 END) as October,
SUM(CASE WHEN month_of_year = 11 THEN 1 ELSE 0 END) as November,
SUM(CASE WHEN month_of_year = 12 THEN 1 ELSE 0 END) as December
FROM datetest
INNER JOIN sys_calendar.calendar cal
ON cal.calendar_date BETWEEN start_date and end_date
GROUP BY record_id;
DROP TABLE datetest;
Because Quarter was mentioned in the question (I'm not sure how it relates here) there is also quarter_of_year and month_of_quarter available in the sys_calendar to slice and dice this even further.
Also, if you are on 16.00+ There is PIVOT functionality which may help get rid of the CASE statements here.
First join with the calendar to get all the dates within the range and get the number of days per each month (incl. full month, not mentioned in Start_Date and End_Date).
Then sum up each month in a column per Range.
create table SplitDateRange ( Range bigint, Start_Date date, End_Date date );
insert into SplitDateRange values ( 1, '2018-10-05', '2018-12-14' );
insert into SplitDateRange values ( 2, '2018-11-20', '2018-12-31' );
insert into SplitDateRange values ( 3, '2018-10-28', '2018-12-02' );
select
Range
, sum(case when mon = 10 then days else 0 end) as "Oct"
, sum(case when mon = 11 then days else 0 end) as "Nov"
, sum(case when mon = 12 then days else 0 end) as "Dec"
from (
select
Range
, extract(MONTH from C.calendar_date) as mon
, max(C.calendar_date) - min(calendar_date) +1 as days
from Sys_Calendar.CALENDAR as C
inner join SplitDateRange as DR
on C.calendar_date between DR.Start_Date and DR.End_Date
group by 1,2
) A
group by Range
order by Range
;
Different approach, avoids the cross join to the calendar by applying Teradata Expand On feature for creating time series. More text, but should be more efficient for larger tables/ranges:
SELECT record_id,
Sum(CASE WHEN mth = 10 THEN days_in_month ELSE 0 END) AS October,
Sum(CASE WHEN mth = 11 THEN days_in_month ELSE 0 END) AS November,
Sum(CASE WHEN mth = 12 THEN days_in_month ELSE 0 END) AS December
FROM
( -- this Derived Table simply avoids repeating then EXTRACT/INTERVAL calculations (can't be done directly in the nested Select)
SELECT record_id,
Extract(MONTH From Begin(expanded_pd)) AS mth,
Cast((INTERVAL( base_pd P_INTERSECT expanded_pd) DAY) AS INT) AS days_in_month
FROM
(
SELECT record_id,
PERIOD(start_date, end_date+1) AS base_pd,
expanded_pd
FROM datetest
-- creates one row per month
EXPAND ON base_pd AS expanded_pd BY ANCHOR PERIOD Month_Begin
) AS dt
) AS dt
GROUP BY 1

Display 12 months of data from the past 5 years

I am currently creating a script that will pull 5 years of invoice data and will summarize the invoice amounts by month of that year for a specific customer. Example
Year jan feb mar
2011 800 900 700
2012 700 800 900, and so forth
I am having issues getting my output to be like this though. My current code
select MAX(cust) as customer,year(invoicedate) as y, month(invoicedate) as m, sum(amount) as summary
from #tquery
group by year(dinvoice), month(dinvoice)
having MAX(ccustno) ='WILLAMETTE'
order by y asc,m asc
select * from #tquery
gives me this. which i just need to find a way to reformat it.
customer year month amount
WILLAMETTE 2012 11 500
WILLAMETTE 2012 12 600
WILLAMETTE 2013 1 600
No need to go through a Pivot. It is only 12 columns. A conditional aggregation would be more efficient
Select Customer = cust
,Year = year(invoicedate)
,Jan = sum(case when month(invoicedate) = 1 then amount else 0 end)
,Feb = sum(case when month(invoicedate) = 2 then amount else 0 end)
...
,Dec = sum(case when month(invoicedate) =12 then amount else 0 end)
From #tquery
Group by ccustno,year(dinvoice)
Order By 1,2
You must using PIVOT to reformat rows to column
select customer
,y
,"1","2","3","4","5","6","7","8","9","10","11","12"
from (select cust as customer,year(invoicedate) as y, month(invoicedate) as m,amount
from #tquery
where ccustno ='WILLAMETTE'
)
t
pivot (sum (amount) for m in ("1","2","3","4","5","6","7","8","9","10","11","12")) p
order by y
;

Transpose data in SQL

Can someone assist me on this?
As you can see from the first picture (Original data) I have date in format "Mar-12" and data for 2014,2015,2016 and 2017 year.
Now, I need to insert new column "year" where I need to put the year from Jan-14, Jan-15, Jan-16, Feb-16 etc.
Basically, I need some kind of data transpose, I think.
In the second picture "Final Order" I show in which order I need the data.
I don't know what is dbms.
So, this is how my data (original) looks like:
Customer|Section|Data|Jan-14|Feb-14|Jan-15|Feb-15
Total Fore SR 10 20 30 35
Total Fore TK 5 4 12 10
===================================================
And I need to put the data in this form:
Customer|Section|Data| Year |Jan|Feb|
Total Fore SR 2014 10 20
Total Fore TK 2014 5 4
Total Fore SR 2015 30 35
Total Fore TK 2015 12 10
Given your sample of
create table t (Customer varchar(5),Section varchar(4), Data varchar(2), [Jan-14] int , [Feb-14] int, [Jan-15] int, [Feb-15] int)
insert into #t values
('Total' , 'Fore' , 'SR' , 10 , 20, 30, 35),
('Total' , 'Fore' , 'TK' , 5 , 4, 12, 10)
you can solve this if your sql dialect is ms sql server by unpivoting and then grouping by like so
select customer,section,data,yyyy,
sum(case when mm='Jan' then dts else 0 end) as 'Jan',
sum(case when mm='Feb' then dts else 0 end) as 'Feb'
from
(
select customer,section,data,
dummy,
substring(dummy,1,3) as mm,
concat('20',substring(dummy,5,2)) as yyyy,
dts
from
(
select customer,section,data,
[Jan-14] , [Feb-14] , [Jan-15] , [Feb-15]
from t
) pvt
UNPIVOT
(dts FOR dummy IN
([Jan-14] , [Feb-14] , [Jan-15] , [Feb-15])
)AS unpvt
) x
group by customer,section,yyyy,data
result
customer section data yyyy Jan Feb
-------- ------- ---- ---- ----------- -----------
Total Fore SR 2014 10 20
Total Fore TK 2014 5 4
Total Fore SR 2015 30 35
Total Fore TK 2015 12 10
If your sql dialect does not have unpivot you can
select customer,section,data,yyyy,
sum(case when mm='Jan' then dts else 0 end) as 'Jan',
sum(case when mm='Feb' then dts else 0 end) as 'Feb'
from
(
select customer,section,data,2014 as yyyy,'Jan' as mm,[Jan-14] as dts from t
union all
select customer,section,data,2014 as yyyy,'Feb' as mm,[Feb-14] as dts from t
union all
select customer,section,data,2015 as yyyy,'Jan' as mm,[Jan-15] as dts from t
union all
select customer,section,data,2015 as yyyy,'Feb' as mm,[Feb-15] as dts from t
) x
group by customer,section,yyyy,data
Clearly either method is a pain if you have an unknown/variable number/lots of columns in which case you would need write a script to generate a sql statement for submission to dynamic sql.

How to calculate a growing or decreasing percentage between rows usign group by

Let's suposse that I have this table_1:
Year Item Qty_sold
2013 1 3
2013 2 2
2013 3 5
2014 1 2
2014 2 3
I'll perform something like this
select year , sum(Qty_sold) as Quantity
from table_1 inner join table_2 on .... inner join table_n
where Year = 2014
The final result depends mostly on the filter by year, but there are other tables involved.
But as a result I need something like this:
Year Quantity Diff_Percentage
2014 5 0.5
Because during the previous year (2013) the final quantity of items sold was 10.
Regards
You seem to want something like this:
select year, sum(Qty_sold) as Quantity,
lag(sum(qty_sold)) over (order by year) as prev_Quantity,
(1 - Quantity / lag(sum(qty_sold)) over (order by year)) as diff_percentage
from table
group by Year;
Of course, this returns the info for all years. If you really just want the year 2014 and 2013 then use conditional aggregation:
select year,
sum(case when year = 2014 then Qty_sold end) as Quantity_2014,
sum(case when year = 2013 then Qty_sold end) as Quantity_2013,
(1 - sum(case when year = 2014 then Qty_sold end)/
sum(case when year = 2013 then Qty_sold end)
) as diff_percentage
from table
where Year in (2013, 2014);
I'm sort of guessing on the formula for diff_percentage, but I think that's what you want.
As per your requirement, please try this
select t.year,qty, (1-qty/prev_qty)
from
(select year, sum(Qty_sold) as qty,
lag(sum(qty_sold)) over (order by year) as prev_qty
from tbl group by Year) t where t.year=in_year --in_year whichever year record you want.
Hope it works for you.

How to maintain a running balance in a month wise report

SELECT *
FROM
(SELECT
YEAR (DateOfTransaction) AS year,
LEFT(DATENAME(MONTH, DateOfTransaction), 3) AS month,
SUM(CASE WHEN TransTypeName LIKE 'credit%' THEN amount ELSE 0 END) -
SUM(CASE WHEN TransTypeName LIKE 'Debit%' THEN amount ELSE 0 END) AS Balance
FROM
.............) AS t
PIVOT (SUM(balance) FOR month IN (jan, feb, march, ...., Dec)) AS pvt
This query returns a month-wise report account balance. I want a result is running balance.
Example:
January month I credit 5000, February month I credit 2000
My query result is
year jan feb march...dec
2014 5000 2000 null ..null
I want a result like this:
year jan feb march...dec
2014 5000 7000 null ..null
(5000+2000)
Try this
SELECT year,Jan = Jan, Feb = isnull(Jan,0)+isnull(Feb,0),....
FROM
(SELECT
YEAR (DateOfTransaction) AS year,
LEFT(DATENAME(MONTH, DateOfTransaction), 3) AS month,
SUM(CASE WHEN TransTypeName LIKE 'credit%' THEN amount ELSE 0 END) -
SUM(CASE WHEN TransTypeName LIKE 'Debit%' THEN amount ELSE 0 END) AS Balance
FROM
.............) AS t
PIVOT (SUM(balance) FOR month IN (jan, feb, march, ...., Dec)) AS pvt)t
Or you can simply add a temp table which stores numbers from 1 to 12
inner join #temp on n>=datepart(mm,DateofTransaction) group by year(transaction), n