I have to do this:
the Total amount of Jobs by Status for the current day
the Total amount of Jobs closed in the last 30 days
My question is how to do that because I have been looking how to do it but I can't find it.
This is the corresponding data:
Select JobStatus, Count(*) as StatusCount
from myTable
where JobStartDate <= currentDate and currentDate < JobEndDate;
Select Count(*) as ClosedCount
from myTable
where JobStatus = 'C' and JobEndDate >= thirtyDaysAgo;
currentDate and thirtyDaysAgo are dependent to your database which you didn't tag.
For question #1:
SELECT JOBSTATUS,COUNT(JOBID)
FROM BTRS_JOBS
WHERE JOBSTARTDATE <= CAST(GETDATE() AS DATE)
AND JOBENDDATE > CAST(GETDATE() AS DATE)
GROUP BY JOBSTATUS
--YOU CAN USE ANY HARDCODED DATE
For question #2:
SELECT COUNT(JOBID) NOOFJOBSCLOSED
FROM BTRS_JOBS
WHERE JOBSTATUS = 'C'
AND JOBENDDATE >= CAST((GETDATE()-30) AS DATE) -- YOU CAN USE ANY HARDCODED DATE
Related
With the query, I basically want to compare avg_clicks at different time periods and set a filter according to the avg_clicks.
The below query gives us avg_clicks for each shop in January 2020. But I want to see the avg_clicks that is higher than 0 in January 2020.
Question 1: When I add the where avg_clicks > 0 in the query, I am getting the following error: Column 'avg_clicks' cannot be resolved. Where to put the filter?
SELECT AVG(a.clicks) AS avg_clicks,
a.shop_id,
b.shop_name
FROM
(SELECT SUM(clicks_on) AS clicks,
shop_id,
date
FROM X
WHERE site = ‘com’
AND date >= CAST('2020-01-01' AS date)
AND date <= CAST('2020-01-31' AS date)
GROUP BY shop_id, date) as a
JOIN Y as b
ON a.shop_id = b.shop_id
GROUP BY a.shop_id, b.shop_name
Question 2: As I wrote, I want to compare two different times. And now, I want to see avg_clicks that is 0 in February 2020.
As a result, the desired output will show me the list of shops that had more than 0 clicks in January, but 0 clicks in February.
Hope I could explain my question. Thanks in advance.
For your Question 1 try to use having clause. Read execution order of SQL statement which gives you a better idea why are you getting avg_clicks() error.
SELECT AVG(a.clicks) AS avg_clicks,
a.shop_id,
b.shop_name
FROM
(SELECT SUM(clicks_on) AS clicks,
shop_id,
date
FROM X
WHERE site = ‘com’
AND date >= '2020-01-01'
AND date <= '2020-01-31'
GROUP BY shop_id, date) as a
JOIN Y as b
ON a.shop_id = b.shop_id
GROUP BY a.shop_id, b.shop_name
HAVING AVG(a.clicks) > 0
For your Question 2, you can do something like this
SELECT
shop_id,
b.shop_name,
jan_avg_clicks,
feb_avg_clicks
FROM
(
SELECT
AVG(clicks) AS jan_avg_clicks,
shop_id
FROM
(
SELECT
SUM(clicks_on) AS clicks,
shop_id,
date
FROM X
WHERE site = ‘com’
AND date >= '2020-01-01'
AND date <= '2020-01-31'
GROUP BY
shop_id,
date
) as a
GROUP BY
shop_id
HAVING AVG(clicks) > 0
) jan
join
(
SELECT
AVG(clicks) AS feb_avg_clicks,
shop_id
FROM
(
SELECT
SUM(clicks_on) AS clicks,
shop_id,
date
FROM X
WHERE site = ‘com’
AND date >= '2020-02-01'
AND date < '2020-03-01'
GROUP BY
shop_id,
date
) as a
GROUP BY
shop_id
HAVING AVG(clicks) = 0
) feb
on jan.shop_id = feb.shop_id
join Y as b
on jan.shop_id = b.shop_id
Start with conditional aggregation:
SELECT shop_id,
SUM(CASE WHEN DATE_TRUNC('month', date) = '2020-01-01' THEN clicks_on END) / COUNT(DISTINCT date) as avg_clicks_jan,
SUM(CASE WHEN DATE_TRUNC('month', date) = '2020-02-01' THEN clicks_on END) / COUNT(DISTINCT date) as avg_clicks_feb
FROM X
WHERE site = 'com' AND
date >= '2020-01-01' AND
date < '2020-03-01'
GROUP BY shop_id;
I'm not sure what comparison you want to make. But if you want to filter based on the aggregated values, use a HAVING clause.
For example
If I want to check in every day last week
select count(ID) from DB where date < "2019/07/01"
select count(ID) from DB where date < "2019/07/02"
select count(ID) from DB where date < "2019/07/03"
...
select count(ID) from DB where date < "2019/07/08"
like
0701 10
0702 15
0703 23
...
0707 45
How to do this without loop and one query?
You can generate the dates using a recursive CTE (or other method) and then run the query:
with dates as (
select convert(date, '2019-07-01') as dte union all
select dateadd(day, 1, dte)
from dates
where dte < '2019-07-08'
)
select d.dte,
(select count(*) from DB where DB.date < d.dte)
from dates d;
More efficient, though, is a cumulative sum:
select db.*
from (select date, count(*) as cnt, sum(count(*)) over (order by date) as running_cnt
from db
group by date
) d
where d.date >= '2019-07-01' and d.date < '2019-07-09';
Are you just counting the number by day?
Something like
SELECT MONTH(date), DAY(date), COUNT(ID)
FROM DB
GROUP BY MONTH(date), DAY(date);
(assuming date is a DATE or DATETIME)
Do it with window Count. range between current row and current row selects exactly this day rows.
select distinct date, count(1) over (order by Date) - count(1) over (order by Date range between current row and current row)
from DB
where date between '2019-07-01' and '2019-07-08';
I assume date column is exactly DATE.
I want to calculate a count of unique users who have posted 5 or more times over the course of a 7-day rolling period. How do I do this?
I know how to calculate a count of users who have posted 1 or more times over the course of a 7-day rolling period. The query looks like this:
with PostsPerDay as (
select cast(CreationDate as Date) [Day]
, OwnerUserId [User]
, count(*) Post
from Posts
where CreationDate > '2017-07-01'
group by
cast(CreationDate as Date)
, OwnerUserId
)
select [Day], count(distinct [User]) DailyPosters, Rolling7DayCount
from PostsPerDay
outer apply (
select count(distinct [User]) Rolling7DayCount
from PostsPerDay ppd
where ppd.[Day] >= dateadd(dd, -7, PostsPerDay.[Day])
and ppd.[Day] < PostsPerDay.[Day]
) Rolling7DayCount
group by [Day], Rolling7DayCount
order by 1
Here it is at the Stack Exchange Data Explorer.
Desired Results
Ideally I'm looking for a four-column result: Day, DailyPosters, Rolling7DayCount, Rolling7DayCount5xPosters. (The sample query returns the first 3 columns.)
To be extra clear: I'm hoping to count users who have posted 5x over the course of any 7 day period ending on a specific date. So simply adding a Having to the CTE won't give me what I need.
Any performance tips would be appreciated, too!
In your "PostsPerDay" CTE change it to this:
SELECT
CAST(CreationDate AS DATE) [Day]
,OwnerUserId
,COUNT(*) Post
FROM
Posts
WHERE
CreationDate > '2017-07-01'
GROUP BY
CAST(CreationDate AS DATE)
,OwnerUserId
HAVING COUNT(*) >= 5
I only added the "HAVING" filter.
After some troubleshooting and a bit of help from Stack Overflow developer #BenjaminHodgson, I figured it out.
Here's the code:
DECLARE #Date1 DATE, #Date2 DATE
SET #Date1 = '20170601' -- start date
SET #Date2 = '20170726';-- end date
with Days as (
SELECT DATEADD(DAY,number+1,#Date1) [Date]
FROM master..spt_values
WHERE type = 'P'
AND DATEADD(DAY,number+1,#Date1) < #Date2
),
-- create calendar of days
cal as (
select *
from Days
),
data as (
select
cal.[Date]
, x.OwnerUserId [User]
, x.PostsLast7Days
from cal
cross apply (
select
OwnerUserId
, count(*) PostsLast7days
from Posts
where CreationDate between dateadd(dd, -7, cal.[Date]) and cal.[Date]
group by OwnerUserId
) x
)
select
distinct Date,
sum(case when PostsLast7days > 0 then 1 else 0 End) [Sent >= 1 Posts in Preceding 7 Days],
sum(case when PostsLast7days >= 5 then 1 else 0 End) [Sent >= 5 Posts in Preceding 7 Days],
sum(case when PostsLast7days >= 10 then 1 else 0 End) [Sent >= 10 Posts in Preceding 7 Days],
sum(case when PostsLast7days >= 20 then 1 else 0 End) [Sent >= 20 Posts in Preceding 7 Days]
from data
group by Date
order by 1 asc
You can see the code in action at the Stack Exchange Data Explorer.
Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 9 years ago.
Improve this question
I got this in a table:
id dateFrom hours
1 2013-02-01 6
2 2013-04-01 8
The hours represent the hours during a month, starting at that date, valid until next record.
I need to know how to sum the hours for month between two dates.
For example if range dates are 2013-02-01 to 2013-06-01:
6hs for february +
6hs for march +
8hs for april +
8hs for may +
8hs for june
========
36 hs
DECLARE #startDate DATE
DECLARE #endDate DATE
SET #startDate = '20130201'
SET #endDate = '20130601'
;WITH CTE_Months AS
(
SELECT #startDate DT
UNION ALL
SELECT DATEADD(MM,1,DT) FROM CTE_Months
WHERE DATEADD(MM,1,DT) <= #endDate
)
,CTE_RN AS
(
SELECT *, ROW_NUMBER() OVER (PARTITION BY DT ORDER BY dateFrom DESC) RN
FROM CTE_Months m
LEFT JOIN Table1 t ON m.DT >= t.dateFrom
)
SELECT SUM(hours)
FROM CTE_RN WHERE RN = 1
First recursive CTE is to find gaps between two dates, second CTE using ROW_NUMBER and JOIN on actual table to find hours for each month. At the end, just sum WHERE RN=1
SQLFiddle DEMO
I get it. The hours represent the hours during a month, starting at that date. You then want to add things up by month.
The following uses a recursive CTE to calculate one day in each month. It then joins to your table, and chooses the most recent row before the current row. Finally, it adds up the hours:
declare #fromdate date = '2013-02-01';
declare #todate date = '2013-06-01';
with months as (
select #fromdate as thedate
union all
select DATEADD(month, 1, thedate)
from months
where DATEADD(month, 1, thedate) <= #todate
),
t as (
select 1 as id, CAST('2013-02-01' as DATE) as datefrom, 6 as hours union all
select 2, '2013-04-01', 8
)
select SUM(hours)
from (select t.*, m.thedate, ROW_NUMBER() over (partition by m.thedate order by t.datefrom desc) as seqnum
from months m join
t
on m.thedate >= t.datefrom
) t
where seqnum = 1;
So the problem is actually two fold here. First we need to normalise it so we get actual month,hourPermonth tuples. We need to create month increments between row n and row n+1 and give them each the hours value of the original table.
I solved it by using an inline table-valued function that you can call or cross apply with parameters.
Complete solution to test here: http://sqlfiddle.com/#!6/b7e58/1
Sample code for the function and how to call it:
CREATE FUNCTION dbo.GetSum(#startDate date,#endDate date)
RETURNS TABLE
AS RETURN
(
WITH cte as
(
SELECT #startDate as s
UNION ALL
SELECT DATEADD(month,1,s)
FROM cte WHERE s<#endDate
)
SELECT
SUM(hours) as sumHours
FROM cte
CROSS APPLY (SELECT top 1 h.hours FROM dbo.hourInterval as h WHERE h.startdate <= cte.s order by h.startdate desc) as t
)
GO
SELECT * FROM dbo.GetSum('2013-02-01','2013-06-01')
I'm building a MySQL query to determine how many items from each of several categories appear in a given date range. My initial attempt looked like this:
select Title,
(select count(*) from entries where CategoryID=1
and Date >= #StartDate and Date <= #EndDate) as Cat1,
(select count(*) from entries where CategoryID=2
and Date >= #StartDate and Date <= #EndDate) as Cat2,
(select count(*) from entries where CategoryID is null
and Date >= #StartDate and Date <= #EndDate) as UnkownCategory
from entries
where Date >= #StartDate and Date <= #EndDate
The table is quite large and I'd like to refactor the query to speed it up, but I'm not sure how - can this be rewritten using GROUP BY/HAVING statements or is there another way I'm missing?
Edit: Sample result set - something like this:
Title | Category 1 Total | Category 2 Total | Unknown Category Total
ABC 1 3 0
DEF 2 7 2
select Title, SUM(CategoryID=1) as Cat1, SUM(categoryID=2) as Cat2,
SUM(categoryID IS NULL) as UnknownCategory
FROM entries
WHERE Date BETWEEN #StartDate AND #EndDate
GROUP BY Title
You can stick expressions in sum() functions: truth equals 1, false equals 0. Also I used the BETWEEN operator which is a little faster.
An alternative that would return a different result layout but is a little conceptually simpler:
select Title, CategoryID, count(*)
from entries
WHERE Date BETWEEN #StartDate AND #EndDate
group by Title, CategoryID
How about grouping by category id then using the having statement to filter out specific categories, like:
select CategoryID, count(*)
from entries
where Date >= #StartDate AND Date <= #EndDate
group by CategoryID
having CategoryID = 1 or CategoryID = 2 or CategoryID is null
If there are multiple titles per category you could group by both fields:
select Title, CategoryID, count(*)
from entries
where Date >= #StartDate AND Date <= #EndDate
group by Title, CategoryID
having CategoryID = 1 or CategoryID = 2 or CategoryID is null
Select COUNT(*), sTitle, CategoryID FROM entries
WHERE Date >= #StartDate and Date <= #EndDate
GROUP BY CategoryID, sTitle