i have some problems with my sql query.
Im selecting some values with a specific date range.
for example 2018-05-01 to 2018-05-13 this is the output.
SUM CalendarWeek
8 18
5 19
If the user will select now a date between 2018-04-01 and 2018-05-13 i want to show a 0 instead when there are no values.
For example:
SUM CalendarWeek
0 13
0 14
0 15
0 16
0 17
8 18
5 19
My Query:
SELECT SUM(Codes) AS 'Sum', CW FROM(
SELECT Count(*) AS 'Codes', DATEPART(wk, ScanDate) AS 'CW',
FROM [Table]
WHERE CONVERT(date, ScanDate, 102) >= '2018-01-01' AND CONVERT(date, ScanDate, 102) <= '2018-05-13'
GROUP BY ScanDate, DATEPART(wk, ScanDate)
UNION ALL
SELECT Count(*) AS 'Codes', DATEPART(wk, ScanDate) AS 'CW', ScanDate
FROM [Table_Archive]
WHERE CONVERT(date, ScanDate, 102) >= '2018-01-01' AND CONVERT(date, ScanDate, 102) <= '2018-05-13'
GROUP BY ScanDate, DATEPART(wk, ScanDate)) test
GROUP BY CW, ScanDate
ORDER BY CW ASC
any ideas how to solve this?
Thanks
First, you have to maintain calender table for such kind of task. If, so then use them. else would need to use recursive cte
declare #stardate date, #enddate date
set #stardate = '2018-04-01'
set #enddate = '2018-05-13'
with t as (
select DATEPART(ISO_WEEK, #stardate) as CalendarWeek
union all
select CalendarWeek+1
from t
where CalendarWeek < DATEPART(ISO_WEEK, #enddate)
)
select t1.sum, coalesce(t.CalendarWeek, 0) CalendarWeek
from t
left join table t1 on t1.CalendarWeek = t.CalendarWeek
SELECT ISNULL(SUM, 0), CalendarWeek
You can use IF in MySQL:
Select IF(sum=null, 0,sum) as sum from table_name
If you don't find solution now from this you can comment again I will give the exact query
Related
I have a table of Tasks where I have records for a particular date. I want to have all dates in one month displayed with numbers of tasks per date. If on some date there were no record of a task it should be written 0.
I have results with duplicating records from the same date when there were tasks on a given day.
Table:
Date Tasks
2021-08-01 0
2021-08-02 0
2021-08-03 0
2021-08-03 25
2021-08-04 0
2021-08-04 18
2021-08-05 0
2021-08-05 31
2021-08-06 0
SQL code I am using:
Declare #year int = 2021, #month int = 8;
WITH numbers
as
(
Select 1 as value
UNion ALL
Select value +1 from numbers
where value + 1 <= Day(EOMONTH(datefromparts(#year, #month, 1)))
)
SELECT datefromparts(#year, #month, numbers.value) AS 'Datum', 0 AS 'Tasks' FROM numbers
UNION
SELECT CONVERT(date, added_d) AS 'Datum', COUNT(*) AS 'Tasks' FROM Crm.Task
WHERE YEAR(added_d) = '2021' AND MONTH(added_d) = '8' GROUP BY CONVERT(date, added_d)
How can I remove duplicates that I will have only one date record 21-08-03 with 25 tasks?
Thank you for your help
You requires OUTER JOIN :
WITH numbers as (
Select datefromparts(#year, #month, 1) as value
UNION ALL
Select DATEADD(DAY, 1, value) as value
from numbers
where value < EOMONTH(value)
)
select num.value, COUNT(tsk.added_d) AS Tasks
from numbers num left join
Crm.Task tsk
on CONVERT(date, tsk.added_d) = num.value
GROUP BY num.value;
If you want all dates for one month, you can do:
with dates as (
select datefromparts(#year, #month, 1) as dte
union all
select dateadd(day, 1, dte)
from dates
where dte < eomonth(dte)
)
You can then incorporate this into the logic using an outer join or subquery:
with dates as (
select datefromparts(#year, #month, 1) as dte
union all
select dateadd(day, 1, dte)
from dates
where dte < eomonth(dte)
)
select d.dte, count(t.added_d)
from dates d left join
Crm.Task t
on convert(date, t.added_d) = d.dte
group by d.dte
order by d.dte;
You can easily extend the logic for the CTE for more than one month, by adjusting the where clause in the second clause.
I'm having trouble to display the last 12 months for each record, can anyone help?
Right now I can only display one month for each record.
DECLARE #DateEnd as DATETIME = DATEADD(month,((YEAR(getdate())-1900)*12) + MONTH(getdate())-1,-1)
-- SET #DateEnd = '20191130'
DECLARE #Frequency_List table (FREQUENCY_ID char(3)); INSERT into #Frequency_List values ('118') -- ('111'),('118'),('110') -- 'MTD','QTD','YTD'
DECLARE #Entity_List table (ENTITY_NAME char(50)); INSERT into #Entity_List values
('F1000'),('R2202'),('R528'),('R810'),('R567'),('R402I'),('R508'),('F1000'),('A950A'),('R557'),('R559'),('R560'),('TBNOBL'),('ALTACORP'),('R590RVME'),('Z490'),('R5070'),('R591'),('R710')
select P.PORTF_CODE, F.EXT_NAME, REPLACE(CONVERT(VARCHAR(10), AKRE.BEGIN_DATE, 102), '.', '-') as 'BEGIN_DATE', REPLACE(CONVERT(VARCHAR(10), AKRE.END_DATE, 102), '.', '-') as 'END_DATE',
ISNULL(AKRE.PTF_END_OAD,0) 'PTF End Duration', ISNULL(AKRE.BMK_END_OAD,0) 'BMK End Duration', (ISNULL(AKRE.PTF_END_OAD,0)-ISNULL(AKRE.BMK_END_OAD,0)) 'Diff End Duration',
ISNULL(AKRE.PTF_END_OAS,0)*10000 'PTF End Spread', ISNULL(AKRE.BMK_END_OAS,0)*10000 'BMK End Spread', (ISNULL(AKRE.PTF_END_OAS,0)-ISNULL(AKRE.BMK_END_OAS,0))*10000 'Diff End Spread',
((ISNULL(AKRE.PTF_END_OAD,0)*(ISNULL(AKRE.PTF_END_OAS,0)*10000))-(ISNULL(AKRE.BMK_END_OAD,0)*(ISNULL(AKRE.BMK_END_OAS,0)*10000))) 'DIF_END_DTS'
from BISAMDW..ATTX_KEY_RATES_EFFECTS AKRE
left join BISAMDW..PORTFOLIO P on P.PORTF_ID = AKRE.PORTF_ID
left join BISAMDW..ATTR_INSTRUMENT AI on AI.ATINS_ID = AKRE.ATINS_ID
left join [BISAMDW].[dbo].[UD_GROUP] GRP on AKRE.USER_DEFINED_GROUP_ID=GRP.USER_DEFINED_GROUP_ID
left join BISAMDW..T_FREQUENCY F on F.FREQUENCY_ID = AKRE.FREQUENCY_ID
where AKRE.END_DATE = #DateEnd and P.PORTF_NAME in ( select ENTITY_NAME from #Entity_List)
and AKRE.PORTF_CONFIG_ID in ( 1 )
and AKRE.FREQUENCY_ID in (select FREQUENCY_ID from #Frequency_List)
and AKRE.PTF_RETURN is NOT null
and GRP.EXT_CODE in ('BARCLAYS','MASTER_2016')
order by 1,2
The result for the columns of start month and end month in sample resultshould be something like this:
MonthStartDate MonthEndDate
2011-04-01 2011-04-30
2011-05-01 2011-05-31
2011-06-01 2011-06-30
2011-07-01 2011-07-31
2011-08-01 2011-08-31
2011-09-01 2011-09-30
2011-10-01 2011-10-31
2011-11-01 2011-11-30
2011-12-01 2011-12-31
....
Thank you!
If what you want is generate a list of month starts and ends for the last 12 months (plus the current month), then one option is to use a recursive query:
with cte as (
select
dateadd(
year,
-1,
datefromparts(year(getdate()), month(getdate()), 1)
) monthStartDate
union all
select dateadd(month, 1, monthStartDate)
where monthStartDate < dateadd(month, -1, getdate())
)
select monthStartDate, eomonth(monthStartDate) monthEndDate from cte
If you are going to use this data several times, then you should store the results of this query in a separate table, which you can then use directly in your queries. This is called a calendar table.
Personally, I would suggest creating a Calendar Table (there are 100's of examples on how to create these), if you simply need the start and end dates of each month. Then getting the start and end dates from that table is trivial:
SELECT MIN(C.CalendarDate) AS MonthStart,
MAX(C.CalendarDate) AS MonthEnd
FROM dbo.Calendar C
WHERE C.CalendarDate >= '20110101'
AND C.CalendarDate < '20200601'
GROUP BY C.CalendarYear,
C.CalendarMonth;
Alternatively, you can use a Tally to generate these on the fly:
DECLARE #StartDate date = '20110101',
#EndDate date = '20200601';
WITH N AS(
SELECT N
FROM (VALUES(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL))N(N)),
Tally AS(
SELECT TOP (SELECT DATEDIFF(MONTH, #StartDate, #EndDate)) ROW_NUMBER() OVER (ORDER BY (SELECT NULL)) -1 AS I
FROM N N1, N N2, N N3, N N4, N N5)
SELECT DATEADD(MONTH, T.I, #StartDate) AS MonthStart,
EOMONTH(DATEADD(MONTH, T.I, #StartDate)) AS MonthEnd
FROM Tally T;
I am trying to get the 30 days report of users, that will return date and total count of users as count created on that date and i did it with this query
Select count(*) As [Count] ,
(SELECT CONVERT(date, AddDate)) As [Date]
from Users
WHERE AddDate >= (SELECT DateAdd(month, -1, Convert(date, GetDate())))
Group By CONVERT(date, AddDate)
it give me only those dates on which any user is created, but i want to show all 30 days either if it has count 0.
Same Case i want to do with monthly report.
i am getting months in which users are created , now i want to change it to get last 12 months from this month and their total users count. For this i am using this query
Select count(*) As [Count] ,
(Select DATEPART( month , DateAdd( month , DATEPART(mm,AddDate) , -1 ) )) as Month
from Users
WHERE AddDate >= (SELECT DateAdd(YEAR, -1, Convert(date, GetDate())))
Group By DATEPART(mm,AddDate)
Using a Calendar CTE:
With NumberSequence ( Number ) as
(
Select 1 as Number
union all
Select Number + 1
from NumberSequence
where Number <= 30
)
, CalendarCTE as
(
select cast(dateadd(dd, -30 + Number,getdate()) as Date) as CalDate
from Numbersequence
)
select CalDate, count(U1.*) as CountUsers
from CalendarCTE
left join Users U1
on CalDate = convert(date, U1.AddDate)
group by CalDate
As I mentioned in comment, You need a Calendar table and Left Join
SELECT Count(u.adddate) AS [Count],
c.dates AS [Date]
FROM calendar_table C
LEFT JOIN users U
ON c.dates = CONVERT(DATE, adddate)
WHERE c.dates >= Dateadd(month, -1, CONVERT(DATE, Getdate()))
GROUP BY c.dates
To generate/create a calendar table or dates check out the below questions
How to generate a range of dates in SQL Server
Generate Dates between date ranges
How to create a Calender table for 100 years in Sql
Try this script :
WITH CTEDates
AS
(
SELECT CAST(GetDate() as date) AS [date]
UNION ALL
SELECT DATEADD(dd, 1, [date])
FROM CTEDates
WHERE DAY([date]) <= 30
)
Select count(*) As [Count] ,CONVERT(date, AddDate) As [Date]
from CTEDates
LEFT JOIN Users ON CTEDates.date=CONVERT(date, AddDate)
WHERE AddDate >= DateAdd(month, -1, GetDate())
Group By CONVERT(date, AddDate)
DECLARE #StartDate Datetime
DECLARE #EndDate Datetime
CREATE TABLE #tMyCalanderDate (dtDate Datetime Primary key)
SELECT #StartDate = '01-Sep-2016'
SELECT #EndDate = '30-Sep-2016'
WHILE #StartDate <= #EndDate
BEGIN
INSERT INTO #tMyCalanderDate (dtDate)
SELECT #StartDate
SELECT #StartDate = DATEADD(day,1,#StartDate)
END
SELECT count(A.UserID) As [Count] , B.dtDate As [Date]
FROM Users AS A
RIGHT JOIN #tMyCalanderDate AS B ON CONVERT(date, A.AddDate) = CONVERT(date, B.dtDate)
WHERE CONVERT(date, A.AddDate) BETWEEN #StartDate AND #EndDate
Group By CONVERT(date, B.dtDate)
You can use a CTE to get a thirty day calendar. Then left join your Users table to it.
DECLARE #CurrentTime DATETIME = GETDATE()
;WITH CTE AS
(
SELECT CONVERT(DATE, #CurrentTime) AS [Date]
UNION ALL
SELECT DATEADD(dd, -1, Date)
FROM CTE
WHERE DATEADD(dd, 29, Date) > #CurrentTime
)
SELECT COUNT(U.AddDate) AS [Count]
, CTE.[Date] AS [Date]
FROM CTE
LEFT JOIN users U
ON CTE.Date = CONVERT(Date, AddDate)
GROUP BY CTE.Date
You can use a similar CTE to get the twelve month calendar and use the same joins to get the count.
HTH.
I need to write an SQL query to produce the following result set. What's the best way to achieve this?
Time Range Qty Amount
===============================================
Last 24 Hours 56 $2000
Last 7 Days 359 $3900
Last 14 Days 2321 $22,888
select 'Last 24 hours'
, sum(Qty) as Qty
, sum(Amount) as Amount
from YourTable
where TradeDt > dateadd(hour, -24, getdate())
union all
select 'Last 7 days'
, sum(Qty)
, sum(Amount)
from YourTable
where TradeDt > dateadd(day, -7, getdate())
union all
select 'Last 14 days'
, sum(Qty)
, sum(Amount)
from YourTable
where TradeDt > dateadd(day, -14, getdate())
My first guess would be to use UNION, if you absolutely need a table as a result (otherwise, you could just fetch the data row by row).
I don't think that there is any nicer way to do this in SQL.
SELECT 'Last 24 hours', SUM(qty), SUM(amount)
FROM table
WHERE datediff(day, getdate(), date) = 1
UNION
SELECT 'Last 7 days', SUM(qty), SUM(amount)
FROM table
WHERE datediff(getdate(), date, 'day') < 7
UNION
SELECT 'Last 14 days', SUM(qty), SUM(amount)
FROM table
WHERE datediff(getdate(), date, 'day') < 14
you can use a where clause on dateAdd like
select * from table
where datefield > DateAdd(d,-1,getdate())
select * from table
where datefield > DateAdd(d,-7,getdate())
select * from table
where datefield > DateAdd(d,-14,getdate())
for day and so on
Given a table:
create table #orders (
orderid int,
orderdatetime datetime
)
What is the best way to write sql to output a report containing the count of orders from the current and previous 24 hours, total orders for the current day and previous 7 days, total orders for the current week and previous 4 weeks, and total orders for the month and previous 6 months?
I'm wondering if this can be efficiently rolled up into a single sql using analytical functions, or if 4 sql statements generating the 4 groups of data is the only (or best) way.
Also, given the hourly/day/week grouping, how would one do that in sql server? Datetimes seem to be a pain in the ass everytime I have to do something like this with them...
Ideas? Put into a SSAS cube and do it from there maybe?
SELECT DATEPART(month, orderdatetime), DATEPART(week, orderdatetime), DATEPART(day, orderdatetime), COUNT(*)
FROM #orders
GROUP BY
DATEPART(month, orderdatetime), DATEPART(week, orderdatetime), DATEPART(day, orderdatetime) WITH ROLLUP
This will group the COUNT's by day, week and month in a single query.
The week rollups will have a NULL in DATEPART(day, orderdatetime) column, the month rollups will have a NULL in both DATEPART(day, orderdatetime) and DATEPART(week, orderdatetime) columns.
To make it for every hour, day, week or month from the current without gaps, use CTE's:
WITH q_hours AS
(
SELECT 0 AS col_hour
UNION ALL
SELECT col_hour + 1
FROM q_hours
WHERE col_hour < 22
),
q_days AS
(
SELECT 0 AS col_day
UNION ALL
SELECT col_day + 1
FROM q_days
WHERE col_day < 31
),
q_months AS
(
SELECT 0 AS col_month
UNION ALL
SELECT col_month + 1
FROM q_months
WHERE col_month < 12
)
SELECT col_month, col_day, col_hour, COUNT(orderid)
FROM q_hours
CROSS JOIN
q_days
CROSS JOIN
q_months
LEFT JOIN
#orders
ON DATEDIFF(month, orderdatetime, GETDATE()) = col_month
AND DATEDIFF(day, orderdatetime, GETDATE()) % 31 = col_day
AND DATEDIFF(hour, orderdatetime, GETDATE()) % 24 = col_hour
GROUP BY
col_month, col_day, col_hour WITH ROLLUP
HAVING (
col_month = 0
AND col_day = 0
AND col_hour IS NOT NULL
) -- all hours within 24 hours from now
OR
(
col_month = 0
AND col_day <= 7
AND col_hour IS NULL
) -- all days within 7 days from now
OR
(
col_month <= 6
AND col_day IS NULL
AND col_hour IS NULL
) -- all months within 6 months from now
You could run the four selects from a "dummy table" or an "identity" table that consists of a single row.
You could have:
SELECT
(<query count of orders current/prev 24 hours>) as <name1>,
(<total orders current + 7 days>) as <name2>,
(<total orders current week + 4 weeks>) as <name3>,
(<total orders month + 6 months>) as <name4>
FROM
<IDENTITY table>;
Because you want different timeframes for each datepart type, using a single query with rollup probably won't give you what you want. I'd consider just unioning them all together similar to something like this...
SELECT DatePartValue = DATEPART(HH, orderdatetime),
Type = 'Hourly',
COUNT(*)
FROM #orders
WHERE orderdatetime > DATEADD(HH, -25, GETDATE())
GROUP BY DATEPART(HH, orderdatetime)
UNION
SELECT DATEPART(DD, orderdatetime),
Type = 'Daily',
COUNT(*)
FROM #orders
WHERE orderdatetime > DATEADD(DD, -8, GETDATE())
GROUP BY DATEPART(DD, orderdatetime)
UNION
SELECT DATEPART(WEEK, orderdatetime),
Type = 'Weekly',
COUNT(*)
FROM #orders
WHERE orderdatetime > DATEADD(WEEK, -5, GETDATE())
GROUP BY DATEPART(WEEK, orderdatetime)
ORDER BY Type, DatePartValue
UNION
SELECT DATEPART(MM, orderdatetime),
Type = 'Monthly',
COUNT(*)
FROM #orders
WHERE orderdatetime > DATEADD(MM, -7, GETDATE())
GROUP BY DATEPART(MM, orderdatetime)
ORDER BY Type, DatePartValue
For results in one row, something like this:
select
orders_day = sum(case when datediff(hour,orderdatetime,getdate()) < 24 then 1 else 0 end)
, orders_week = sum(case when datediff(day,orderdatetime,getdate()) < 7 then 1 else 0 end)
, orders_month = sum(case when datediff(week,orderdatetime,getdate()) < 4 then 1 else 0 end)
, orders_half = sum(case when datediff(month,orderdatetime,getdate()) < 6 then 1 else 0 end)
from #orders
You may want to fine tune the date criteria to get appropriate behavior.
For multiple rows, take the results above and transpose it with UNPIVOT or CASE .. CROSS JOIN.
SELECT
sum(case when orderdatetime between GetDate() - 1 and GetDate() then 1 else 0 end) as Current24Hours,
sum(case when orderdatetime between GetDate() - 2 and GetDate() - 1 then 1 else 0 end) as Previous24Hours,
sum(case when orderdatetime between GetDate() - 7 and GetDate() then 1 else 0 end) as Current7Days,
sum(case when orderdatetime between GetDate() - 14 and GetDate() - 7 then 1 else 0 end) as Previous7Days,
sum(case when DATEDIFF (m, OrderDate, #now) <= 1 then 1 else 0 end) as PreviousMonth,
sum(case when DATEDIFF (m, OrderDate, #now) <= 6 then 1 else 0 end) as PreviousSixMonths
FROM orders
I think you want grouping sets. I've understand that sql server supports grouping sets.
EDIT1: I've read that sql server 2005 doesn't support grouping sets but sql server 2008 does. Here an interesting read on a presumed but not existing difference between mapreduce and an rdbms like Oracle and Sql Server. Please read the comments too!! http://www.data-miners.com/blog/2008/01/mapreduce-and-sql-aggregations.html