How to display date less that 1 month from getdate? - sql

I have a report that shows result based on period (e.g: 1 month period, 2 month period...). I try to query and come out like this. As i would like to get record 1 month from current date
SELECT printed_serial,[name],last_active_date
FROM #Temp t
INNER JOIN [dbfastsconfigdataref].[dbo].[cdf_micard] mi on mi.cu_id = t.cu_id
INNER JOIN [dbfastsconfigdataref].[dbo].[cdf_ch_cuid] chcu on chcu.cu_id = t.cu_id
INNER JOIN [dbfastsconfigdataref].[dbo].[cdf_ch] ch on ch.ch_id = chcu.ch_id
WHERE last_active_date <= DATEADD(month, -1, getdate())
with result:
card id name last_active_date
0110 Sara jan 4 2019 4:15 pm
0111 Ara Nov 26 2013 12:22 am
but expected result :
card id name last_active_date
0110 Sara jan 4 2019 4:15 pm

You can try below - using date comparison between one month before and current date
SELECT printed_serial,[name],last_active_date
FROM #Temp t
INNER JOIN [dbfastsconfigdataref].[dbo].[cdf_micard] mi on mi.cu_id = t.cu_id
INNER JOIN [dbfastsconfigdataref].[dbo].[cdf_ch_cuid] chcu on chcu.cu_id = t.cu_id
INNER JOIN [dbfastsconfigdataref].[dbo].[cdf_ch] ch on ch.ch_id = chcu.ch_id
WHERE last_active_date >= DATEADD(month, -1, getdate())
and last_active_date <=getdate()

You are really only interested in month and year, so you can use following:
SELECT printed_serial,[name],last_active_date
FROM #Temp t
INNER JOIN [dbfastsconfigdataref].[dbo].[cdf_micard] mi on mi.cu_id = t.cu_id
INNER JOIN [dbfastsconfigdataref].[dbo].[cdf_ch_cuid] chcu on chcu.cu_id = t.cu_id
INNER JOIN [dbfastsconfigdataref].[dbo].[cdf_ch] ch on ch.ch_id = chcu.ch_id
WHERE MONTH(last_active_date) = MONTH(DATEADD(month, -1, getdate()))
AND YEAR(last_active_date) = YEAR(DATEADD(month, -1, getdate()))

Related

Join table with dates list - include reference on NULLs

More brain freeze moments from me. I'm sure this will be an easy one.
I have two tables. One is a list of part usage by week. This is called TransactionsPerWeek and looks like this:
ItemPK xWeek xYear TotalQty
1234 2 2019 65
1234 4 2019 15
1234 5 2019 50
I also have a DateList table that has week numbers and years in it
xWeek xYear
1 2019
2 2019
3 2019
etc.
When I right join the two together on week and year I get
ItemPK xWeek xYear TotalQty
NULL 1 2019 0
1234 2 2019 65
NULL 3 2019 0
1234 4 2019 15
1234 5 2019 50
What I need is to have the ItemPK on every line, even if the TotalQty is 0. So in effect, I need:
ItemPK xWeek xYear TotalQty
1234 1 2019 0
1234 2 2019 65
1234 3 2019 0
1234 4 2019 15
1234 5 2019 50
This is my code...
SELECT itemfk,
dates.year,
dates.week,
isnull(transactionsperweek.TotalQty,0) as TotalQty
from (
SELECT iit.ItemFK,
year(iit.transactiondate) xYear,
datepart(wk,iit.transactiondate) xWeek,
abs(sum(iit.quantity)) TotalQty
from iteminventorytransaction iit
INNER JOIN ItemInventoryTransactionType iitt on ItemInventoryTransactionTypePK = iit.ItemInventoryTransactionTypeFK
where iit.itemfk = 5311
and iit.ItemInventoryTransactionTypeFK in (10,8)
and iit.TransactionDate BETWEEN
-- 1 year up to the sunday of last week
DateAdd(wk,-51,DATEADD(day,-1 - (DATEPART(weekday, GETDATE()) + ##DATEFIRST - 2) % 7,GETDATE()))
AND DATEADD(day,-1 - (DATEPART(weekday, GETDATE()) + ##DATEFIRST - 2) % 7,GETDATE())
AND Quantity < 0
group by iit.itemfk,
year(iit.transactiondate),
datepart(wk,iit.transactiondate)
) transactionsPerWeek
RIGHT JOIN (
select year,
week
from DatesList
where date > DateAdd(wk,-51,DATEADD(day,-1 - (DATEPART(weekday, GETDATE()) + ##DATEFIRST - 2) % 7,GETDATE()))
AND date < DATEADD(day,-1 - (DATEPART(weekday, GETDATE()) + ##DATEFIRST - 2) % 7,GETDATE())
group by year,
week
) Dates ON dates.week = transactionsPerWeek.xWeek
AND dates.year = transactionsPerWeek.xYear
where week not in (52,53)
Hope this is clear enough. Thanks in advance.
You can use recursive cte :
with cte as (
select 1 as id, max(xWeek) as maxwk
from TransactionsPerWeek
union all
select id + 1, maxwk
from cte c
where c.id < maxwk
)
select coalesce(wk.ItemPK, wk1.ItemPK) as ItemPK, c.id as xWeek, wk.xYear, wk.TotalQty
from cte c left join
TransactionsPerWeek wk
on wk.xWeek = c.id outer apply
( select top (1) wk1.ItemPK
from TransactionsPerWeek wk1
where wk1.xWeek >= c.id and wk1.xWeek is not null
order by wk1.xWeek
) wk1;
Ok, so I did what #larnu suggested and cross joined the item with the dates, then left joined it to the transactionsperweek table and it worked. Thank you.
This is my code now;
SELECT itempk, week, year
, ISNULL(transactionsPerWeek.TotalQty,0) as TotalQty
from item
CROSS JOIN
(
select year, week from DatesList where date >
DateAdd(wk,-51,DATEADD(day,-1 - (DATEPART(weekday, GETDATE()) + ##DATEFIRST - 2) % 7,GETDATE()))
AND date <
DATEADD(day,-1 - (DATEPART(weekday, GETDATE()) + ##DATEFIRST - 2) % 7,GETDATE())
group by year, week
) dates
LEFT JOIN
(
SELECT iit.ItemFK, year(iit.transactiondate) xYear, datepart(wk,iit.transactiondate) xWeek, abs(sum(iit.quantity)) TotalQty from iteminventorytransaction iit
INNER JOIN ItemInventoryTransactionType iitt on ItemInventoryTransactionTypePK = iit.ItemInventoryTransactionTypeFK
where iit.itemfk = 5311 and iit.ItemInventoryTransactionTypeFK in (10,8)
and iit.TransactionDate BETWEEN
-- 1 year up to the sunday of last week
DateAdd(wk,-51,DATEADD(day,-1 - (DATEPART(weekday, GETDATE()) + ##DATEFIRST - 2) % 7,GETDATE()))
AND
DATEADD(day,-1 - (DATEPART(weekday, GETDATE()) + ##DATEFIRST - 2) % 7,GETDATE())
AND Quantity < 0
group by iit.itemfk, year(iit.transactiondate), datepart(wk,iit.transactiondate)
) transactionsPerWeek
ON itempk = transactionsperweek.ItemFK and transactionsPerWeek.xYear = dates.year and transactionsPerWeek.xWeek = dates.week
where itempk = 5311
Use a cross join to generate the rows and a left join to bring in the results you already have.
Your question explicitly states that you have two tables. Hence, I don't know what your SQL code is doing, because it is not referencing those tables. So, based on the description:
select i.ItemPK, d.xWeek, d.xYear,
coalesce(TotalQty, 0) as TotalQty
from (select distinct itemPK from TransactionsPerWeek
) i cross join
DateList d left join
TransactionsPerWeek t
on t.itemPK = i.itemPK and
t.xWeek = d.xWeek and
t.xYear = d.xYear;
Of course if the "tables" are really subqueries, then I would recommend using CTEs and still this basic query structure.

SQL Splitting SUM Rows into Columns based on Dates

I am trying to SUM values into columns based on dates.
This is my current SQL
SELECT DISTINCT
FORMAT(dbo.DR_INVLINES.TRANSDATE, 'MMM') AS Month,
dbo.DR_ACCS.NAME,
SUM(dbo.DR_INVLINES.QUANTITY * dbo.STOCK_ITEMS.X_LITERAGE) AS SUMQTY,
FORMAT(dbo.DR_INVLINES.TRANSDATE, 'yy') AS Year
FROM
dbo.DR_INVLINES
INNER JOIN
dbo.DR_TRANS ON dbo.DR_INVLINES.HDR_SEQNO = dbo.DR_TRANS.SEQNO
INNER JOIN
dbo.STOCK_ITEMS ON dbo.DR_INVLINES.STOCKCODE = dbo.STOCK_ITEMS.STOCKCODE
INNER JOIN
dbo.DR_ACCS ON dbo.DR_INVLINES.ACCNO = dbo.DR_ACCS.ACCNO
GROUP BY
FORMAT(dbo.DR_INVLINES.TRANSDATE, 'yy'),
FORMAT(dbo.DR_INVLINES.TRANSDATE, 'MMM'),
dbo.STOCK_ITEMS.STOCKGROUP, dbo.DR_ACCS.NAME
HAVING
(dbo.STOCK_ITEMS.STOCKGROUP = 3)
This query returns this result set:
Mth Name SUMQTY Year
-----------------------------
Apr Company 1 1000 16
Apr Company 2 30790.4 16
Apr Company 3 1840 16
Apr Company 1 6502.9 17
Apr Company 2 2000 17
Apr Company 3 1000 17
What I am trying to achieve is
Mth Name 2016 2017
-------------------------------
Apr Company 1 800 200
Apr Company 2 15000 13000
Apr Company 3 600 569
Apr Company 1 5000 1500
Apr Company 2 2000 1986
Apr Company 3 1000 2543
Can someone please help with this..... I have been racking my brain for ages on this one ;-)
If I understand your question, you wanted to display YEAR as column,
SELECT FORMAT(dbo.DR_INVLINES.TRANSDATE, 'MMM') AS Month,
dbo.DR_ACCS.NAME,
SUM(CASE WHEN YEAR(dbo.DR_INVLINES.TRANSDATE) = 2016
THEN dbo.DR_INVLINES.QUANTITY * dbo.STOCK_ITEMS.X_LITERAGE
ELSE 0
END ) AS [2016],
SUM(CASE WHEN YEAR(dbo.DR_INVLINES.TRANSDATE) = 2017
THEN dbo.DR_INVLINES.QUANTITY * dbo.STOCK_ITEMS.X_LITERAGE
ELSE 0
END ) AS [2017]
FROM dbo.DR_INVLINES
INNER JOIN dbo.DR_TRANS
ON dbo.DR_INVLINES.HDR_SEQNO = dbo.DR_TRANS.SEQNO
INNER JOIN dbo.STOCK_ITEMS
ON dbo.DR_INVLINES.STOCKCODE = dbo.STOCK_ITEMS.STOCKCODE
INNER JOIN dbo.DR_ACCS
ON dbo.DR_INVLINES.ACCNO = dbo.DR_ACCS.ACCNO
WHERE dbo.STOCK_ITEMS.STOCKGROUP = 3
GROUP BY FORMAT(dbo.DR_INVLINES.TRANSDATE, 'yy'),
FORMAT(dbo.DR_INVLINES.TRANSDATE, 'MMM'),
dbo.STOCK_ITEMS.STOCKGROUP,
dbo.DR_ACCS.NAME
Have you tried group by?
SELECT FORMAT(il.TRANSDATE, 'MMM') AS Month, a.NAME,
SUM(CASE WHEN year(il.TRANSDATE) = 2016 THEN anil.QUANTITY * si.X_LITERAGE END) AS SUMQTY_2017,
SUM(CASE WHEN year(il.TRANSDATE) = 2017 THEN anil.QUANTITY * si.X_LITERAGE END) AS SUMQTY_2016
FROM dbo.DR_INVLINES il INNER JOIN
dbo.DR_TRANS t
ON il.HDR_SEQNO = t.SEQNO INNER JOIN
dbo.STOCK_ITEMS si
ON il.STOCKCODE = si.STOCKCODE INNER JOIN
dbo.DR_ACCS a
ON il.ACCNO = a.ACCNO
WHERE si.STOCKGROUP = 3
GROUP BY FORMAT(il.TRANSDATE, 'MMM'), a.NAME;
Note the changes:
Table aliases make the query easier to write and to read.
The having clause is on an unaggregated column, so it should be a where clause.
You had an extra column in the group by.
I would recommend using datepart() or datename() over format().

calculate multiple total sales of months

My desired output is shown below.I have tried to achieve it like this
*new_card_total = total sales
SELECT DATENAME(MONTH, cl.nc_timestamp) as MonthName,
COUNT(*) as new_card_qty,
ISNULL(sum(cl.nc_deposit),0) as new_card_total
FROM dbfastshosted.dbo.fh_mf_new_card_logs cl
INNER JOIN dbfastshosted.dbo.fh_sales_map m
on cl.nc_log_id = m.nc_log_id
INNER JOIN dbfastshosted.dbo.fh_sales_logs sl
on m.sales_id = sl.sales_id
INNER JOIN dbfastsconfigdataref.dbo.cdf_terminal_user_account h
on cl.created_user_id = h.terminal_user_id
INNER JOIN dbfastsconfigdataref.dbo.cdf_terminal t
on h.terminal_id = t.terminal_id
INNER JOIN dbfastsconfigdataref.dbo.cdf_cuid c
on cl.cu_id = c.cu_id
INNER JOIN dbfastsconfigdataref.dbo.cdf_card_role cr
on cr.id = c.card_role_id
INNER JOIN dbfastshosted.dbo.fh_mf_top_up_logs tl
on tl.tu_log_id = m.tu_log_id
WHERE YEAR(cl.nc_timestamp)= 2017
and cl.currency_id = 1
and (cr_log_id is null or cr_log_id = 0)
and top_up_status = 1
GROUP BY DATENAME(MONTH,cl.nc_timestamp), DATEPART(MONTH, cl.nc_timestamp)
union all
SELECT DATENAME(MONTH, cl.nc_timestamp) as MonthName,
COUNT(*) as new_card_qty,
ISNULL(sum(cl.nc_deposit),0) as new_card_total
FROM dbfastshosted.dbo.fh_mf_new_card_logs cl
INNER JOIN dbfastshosted.dbo.fh_sales_map m
on cl.nc_log_id = m.nc_log_id
INNER JOIN dbfastshosted.dbo.fh_sales_logs sl
on m.sales_id = sl.sales_id
INNER JOIN dbfastsconfigdataref.dbo.cdf_terminal_user_account h
on cl.created_user_id = h.terminal_user_id
INNER JOIN dbfastsconfigdataref.dbo.cdf_terminal t
on h.terminal_id = t.terminal_id
INNER JOIN dbfastsconfigdataref.dbo.cdf_cuid c
on cl.cu_id = c.cu_id
INNER JOIN dbfastsconfigdataref.dbo.cdf_card_role cr
on cr.id = c.card_role_id
INNER JOIN dbfastshosted.dbo.fh_trans tr
on tr.trans_id = m.trans_id
WHERE YEAR(cl.nc_timestamp)= 2017
and cl.currency_id = 1
and (cr_log_id is null or cr_log_id = 0)
GROUP BY DATENAME(MONTH,cl.nc_timestamp), DATEPART(MONTH, cl.nc_timestamp)
with output :
monthname new_card_qty new_card_value
-----------------------------------------------------------
jan 100 1000
feb 200 2000
march 300 3000
march 400 5000
april 500 6000
april 500 8000
and i would like to have output like this:
monthname new_card_qty new_card_total
-----------------------------------------------------------
jan 100 1000
feb 200 2000
march 700 8000
april 1000 13000
I have tried many ways but couldnt make it.Can you please take a look on this? I really need help. Thanks!
It can be achieved by Subquery and group by as below:
SELECT MonthName, SUM(new_card_qty), SUM(new_card_value)
FROM
(SELECT DATENAME(MONTH, cl.nc_timestamp) as MonthName, COUNT(*) as new_card_qty, ISNULL(sum(cl.nc_deposit),0) as new_card_total
FROM dbfastshosted.dbo.fh_mf_new_card_logs cl ........
union all
SELECT DATENAME(MONTH, cl.nc_timestamp) as MonthName, COUNT(*) as new_card_qty, ISNULL(sum(cl.nc_deposit),0) as new_card_total
FROM dbfastshosted.dbo.fh_mf_new_card_logs cl ......) AS A
GROUP BY MonthName

SQL: add missing months from different years

SQL SERVER
[CreatedOn] - DATETIME
I get this table:
Year Month Count
2009 7 1
2009 9 1
2010 1 2
2010 3 13
From query:
SELECT
YEAR ([CreatedOn]) AS 'Year',
MONTH ([CreatedOn]) AS 'Month',
COUNT ([CreatedOn]) AS 'Count'
FROM xxx
GROUP BY YEAR ([CreatedOn]), MONTH ([CreatedOn])
How can I get table like this (with missed months and Count 0):
Year Month Count
2009 7 1
2009 8 0
2009 9 1
2009 10 0
2009 11 0
2009 12 0
2010 1 2
2010 2 0
2010 3 13
Syntax says you are using MSSQL. Use Recursive CTE to generate the calender table then do a Left outer join with XXX table
DECLARE #maxdate DATE = (SELECT Max([CreatedOn])
FROM xxx);
WITH calender
AS (SELECT Min([CreatedOn]) dates,
FROM xxx
UNION ALL
SELECT Dateadd(mm, 1, dates)
FROM cte
WHERE dates < #maxdate)
SELECT Year(dates) [YEAR],
Month(dates) [month],
Count ([CreatedOn]) AS 'Count'
FROM calender a
LEFT OUTER JOIN xxx b
ON Year(dates) = Year ([CreatedOn])
AND Month(dates) = Month ([CreatedOn])
GROUP BY Year(dates),
Month(dates)
Note : Instead of Recursive CTE create a physical calender table
This will use a build in table to create the calendar:
;WITH limits as
(
SELECT min([CreatedOn]) mi, max([CreatedOn]) ma
FROM xxx
), months as(
SELECT
dateadd(mm, number, mi) m
FROM
master..spt_values v
JOIN
limits l
ON
number between 0 and datediff(mm, l.mi, l.ma)
WHERE
v.type = 'P'
)
SELECT
year(months.m) year,
month(months.m) month,
count(qry.[CreatedOn]) cnt
FROM
xxx qry
RIGHT JOIN
months
ON
months.m = dateadd(mm, datediff(mm, 0, qry.[CreatedOn]), 0)
GROUP BY
year(months.m),
month(months.m)

SQL Server : calculate monthly total sales incl empty months

I'm trying to calculate the total sales of a product in a month, but I would like it to include any "empty" months (with no sales) and only select the latest 12 months.
This is my code so far.
declare
#ProductNo int
set #ProductNo = 1234
SELECT
YEAR(o.OrderDate) as 'Year', MONTH(o.OrderDate) as 'Month', sum(Amount) as 'Units sold',[ProductNo]
FROM [OrderLine] ol
inner join [Order] o on ol.OrderNo = o.OrderNo
where ProductNo = #ProductNo
Group by ProductNo, YEAR(o.OrderDate), Month(o.OrderDate)
Order by ProductNo, YEAR(o.OrderDate), Month(o.OrderDate)
This returns
Year Month Units sold
2011 6 2
2011 10 1
2011 11 1
2012 2 1
But I would like it to return.
Year Month Units sold
2011 4 0
2011 5 0
2011 6 2
2011 7 0
2011 8 0
2011 9 0
2011 10 1
2011 11 1
2011 12 0
2012 1 0
2012 2 2
2012 3 0
I'm using SQL Server 2008 R2 Sp1
I've done before I know that you have calendar table. I've used master.dbo.spt_values to generate last twelve consecutive months (including current).
declare #ProductNo int
set #ProductNo = 1234
select MONTH(d.date), YEAR(d.date), isnull(t.amnt, 0) as [Units sold] from (
SELECT
YEAR(o.OrderDate) as 'Year',
MONTH(o.OrderDate) as 'Month',
sum(Amount) as amnt,
[ProductNo]
FROM [OrderLine] ol
inner join [Order] o on ol.OrderNo = o.OrderNo
where ProductNo = #ProductNo
group by ProductNo, YEAR(o.OrderDate), Month(o.OrderDate)
) t
right join (
select dateadd(mm, -number, getdate()) as date
from master.dbo.spt_values
where type = 'p' and number < 12
) d on year(d.date) = t.[year] and month(d.date) = t.[month]
order by YEAR(d.date), MONTH(d.date)
Try:
;with CTE as
(select 0 months_ago union all
select months_ago - 1 months_ago from CTE where months_ago > -11),
month_list as
(select dateadd(MONTH,
months_ago,
dateadd(DAY,
1-datepart(DAY,getdate()),
cast(GETDATE() as DATE))) month_start
from cte)
SELECT YEAR(ml.start_date) as 'Year',
MONTH(ml.start_date) as 'Month',
sum(Amount) as 'Units sold',[ProductNo]
FROM month_list ml
left join [Order] o
on o.OrderDate >= ml.start_date and
o.OrderDate < dateadd(MONTH, 1, ml.start_date)
left join [OrderLine] ol
on ol.OrderNo = o.OrderNo and ProductNo = #ProductNo
Group by ProductNo, YEAR(ml.start_date), Month(ml.start_date)
Order by ProductNo, YEAR(ml.start_date), Month(ml.start_date)