I have a dataset where I have some daily observations. I want to group them by date and later take the average of the daily Sum per day (in SQL).
The SQL used to group by day looks like this and works.
"SELECT Date, Sum(Margin) FROM [OpenPositions] GROUP BY Date"
I have tried the following code to do the intended query in one SQL.
"SELECT Datepart(week, Date),
Avg(avgmargin)
FROM (SELECT Datepart(year, Date) Year,
Datepart(week, Date) Week,
Sum(Margin) sum
FROM [OpenPositions]
GROUP BY Datepart(year, Date),
Datepart(week, Date)"
But this does not work (not showing any data). Can anyone find the mistake in my sql query, and how to come around it?
All help appreciated.
Try this:
Select Datepart(week, Date), Avg(avgmargin) from (
SELECT Date, Sum(Margin) AS Margin FROM [OpenPositions] GROUP BY Date)
Group By Datepart(week, Date)
Edit #2
Try This:
Select TBL.week, Avg(TBL.margin) from (
SELECT Datepart(week, Date) as week ,Datepart(day, Date), Sum(Margin) AS margin
FROM [OpenPositions] GROUP BY Datepart(week, Date),Datepart(day, Date)) as TBL
Group By TBL.week
#calc16 in regard to your response bellow, why don't you do this:
Select TBL.week, Avg(TBL.margin) from
(SELECT Datepart(week, Date) as week, Date, Sum(Margin) AS margin FROM[OpenPositions]
GROUP BY Datepart(week, Date), Date) as TBL
Group By TBL.week
Edit #4
you should add the year to the group in the inner query.
Select TBL.week, , Avg(TBL.margin) from
(SELECT Datepart(week, Date) as week,Datepart(year, Date) as year, Date, Sum(Margin) AS margin FROM[OpenPositions]
GROUP BY Datepart(week, Date), Datepart(year, Date) ,Date) as TBL
Group By TBL.week, TBL.year
Related
I have a table that looks like this:
timestamp | commodity | amount | price |
I am trying to get the weighted average of a commodity ,for each day from the last 7 days(In order to create a graph, c# program), I managed to create a query to get the weighted average:
SELECT SUM(price * amount),
SUM(amount)
FROM [table_name]
WHERE (commodity = #commodity)
AND (timestamp >= #fromDate
AND timestamp <= #toDate);
So, I send this query 7 times, each time adding (-1) to the fromDate and toDate, to get the averages of last 7 days.
I would like to ask if there is a way to do this in 1 query, and if there is, if it can be implemented to get the same information of the last month.
you can use convert to date and do code as below:
SELECT convert(date, timestamp) as [Dates],
SUM(price * amount),
SUM(amount)
FROM [table_name]
WHERE (commodity = #commodity)
AND (timestamp >= #fromDate
AND timestamp <= #toDate)
GROUP BY convert(date, timestamp)
you have to group by date
SELECT SUM(price* amount),SUM(amount) FROM [table_name] WHERE (commodity = #commodity) AND (cast(timestamp as date)>= #fromDate AND cast(timestamp as date)<= #toDate)
Group By cast(timestamp as date)
You should to group your data by date:
SELECT SUM(price * amount),SUM(amount)
FROM [table_name]
WHERE (commodity = #commodity)
AND (timestamp >= #fromDate
AND timestamp <= #toDate)
GROUP BY CAST(timestamp as DATE);
To generate dates, you can use as below:
;with Datescte as (
Select top (datediff(day, #fromDate, #toDate) +1) Dt = Dateadd(day, Row_Number() over (order by (Select null))-1, #fromDate)
from master..spt_values s1, master..spt_values s2
), cte2 as (
SELECT convert(date, timestamp) as [Dates],
SUM(price * amount) as [Sum_Price_Amount],
SUM(amount) as [Sum_Amount]
FROM [table_name]
WHERE (commodity = #commodity)
AND (timestamp >= #fromDate
AND timestamp <= #toDate)
GROUP BY convert(date, timestamp)
)
Select Dt as [Dates] , Sum_Price_Amount, Sum_Amount
FROM Datescte d
LEFT JOIN cte2 d2
ON d.Dt = d2.Dates
I have a dataset that I need to prune on a daily basis. It is populated from a process that writes records into a table periodically.
I currently have a simple query that does this:
DELETE FROM dataTable WHERE entryDate < dateadd(day, -5, GETDATE())
But the problem is that the process is unreliable; there may be days where no data is written at all.
So what I really need is a query that goes back 5 (possibly non-consecutive) days in which data is written, not 5 calendar days.
For example, if I run the following query:
SELECT cast(entryDate as date) as LogDate
FROM dataTable
group by category, cast(entryDate as date)
order by cast(entryDate as date) desc
I might get as a result:
Category Date
Foo 2015-11-30
Foo 2015-11-29
Foo 2015-11-26
Foo 2015-11-25
Foo 2015-11-21
Foo 2015-11-20 <-- Start Pruning here, not the 25th.
Foo 2015-11-19
Foo 2015-11-18
Bar 2015-11-30
Bar 2015-11-29
Bar 2015-11-28
Bar 2015-11-27
Bar 2015-11-26
Bar 2015-11-25 <-- This one is OK to prune at the 25th.
Bar 2015-11-24
Bar 2015-11-23
I need the query to go all the way back to the 20th before it deletes.
You can use row_number to get the last 5 days when the table had an entry. Then delete based on the generated numbers.
SQL Fiddle
with rownums as (SELECT row_number() over(partition by category order by cast(entryDate as date) desc) as rn
,*
FROM dataTable
)
delete from rownums where rn <= 5 --use > 5 for records prior to the last 5 days
Use dense_rank to number the rows if there can be multiple entries per day.
with rownums as (SELECT dense_rank() over(partition by category order by cast(entryDate as date) desc) as rn
,*
FROM dataTable)
delete from rownums where rn > 5;
Try maybe something like this.
;WITH orderedDates (LogDate, RowNum)
AS
(
SELECT [CACHEDATE] AS LogDate, ROW_NUMBER() OVER (ORDER BY CACHEDATE DESC) AS RowNum
FROM
dataTable
GROUP BY CACHEDATE
)
DELETE dataTable
WHERE CACHEDATE IN
(SELECT LogDate FROM orderedDates
WHERE ROWNUM > 5) --or however many you need to go back
I have a table named Leave it contains 2 rows
no=1 Leave=CL,Lnumber=2,FromDate='2015-01-10',ToDate=2015-01-11'
no=2 Leave=CL,Lnumber=2,FromDate='2015-01-12',ToDate=2015-01-13'
no=3 Leave=CL,Lnumber=2,FromDate='2015-01-15',ToDate='2015-02-16'
no=4 Leave=CL,Lnumber=2,FromDate='2015-01-31',ToDate='2015-02-01'
Here I want to get january month leave report(leave and Lnumer). How can I fetch this considering this FromDate and ToDate
The answer should be like this
Leave=CL,Lnumber=7 (for jan month)
Leave=Cl,Lnumber=1 (for feb month)
I am using MSSQL 2008. You can add extra fields if it is necessory. Thank You
I'd recommend building a calendar table (basically a tally table, but with dates). Then join your leave table to the calendar table between the from and to dates, and count the days that fall in the interval.
;with t as
(
select no=1, Leave='CL',Lnumber=2,FromDate=cast('2015-01-10' as date),ToDate=cast('2015-01-11' as date) union all
select no=2, Leave='CL',Lnumber=2,FromDate=cast('2015-01-31' as date),ToDate=cast('2015-02-01' as date)
), cal as
(
select top 10000 _date = cast(cast(row_number() over (order by (select null)) + 41000 as datetime) as date)
from sys.objects a, sys.objects b
)
select
t.Leave,
_year = datepart(year, c._date),
_month = datepart(month, c._date),
count(_date)
from t
inner join cal c
on c._date between t.FromDate and t.ToDate
group by t.Leave, datepart(year, c._date), datepart(month, c._date)
My data looks like below.
How can I find missing date range from ss table.
I want to find missing(ss date range) date range between se_startdate and se_enddate.
for example above.
Missing date ranges are
2014-07-01 to 2014-07-06
2014-07-18 to 2014-07-30.
There may be a simpler way to do this, but often when trying to find missing numbers/dates you need to create those numbers/dates then LEFT JOIN to your existing data to find what is missing. You can create the dates in question with a recursive cte:
WITH cal AS (SELECT CAST('2014-07-01' AS DATE) dt
UNION ALL
SELECT DATEADD(DAY,1,dt)
FROM cal
WHERE dt < '2014-07-30')
SELECT *
FROM cal
Then, you LEFT JOIN to your table to get a list of missing dates:
WITH cal AS (SELECT CAST('2014-07-01' AS DATE) dt
UNION ALL
SELECT DATEADD(DAY,1,dt)
FROM cal
WHERE dt < '2014-07-30')
SELECT DISTINCT cal.dt
FROM cal
LEFT JOIN YourTable a
ON cal.dt BETWEEN CAST(SS_StartDate AS DATE) AND CAST(SS_EndDate AS DATE)
WHERE a.SS_StartDate IS NULL
Then you need to find out whether or not consecutive rows belong in the same range, or if they have a gap between them, using DATEDIFF() and ROW_NUMBER():
WITH cal AS (SELECT CAST('2014-07-01' AS DATE) dt
UNION ALL
SELECT DATEADD(DAY,1,dt)
FROM cal
WHERE dt < '2014-07-30')
,dt_list AS (SELECT DISTINCT cal.dt
FROM cal
LEFT JOIN YourTable a
ON cal.dt BETWEEN CAST(SS_StartDate AS DATE) AND CAST(SS_EndDate AS DATE)
WHERE a.SS_StartDate IS NULL)
SELECT dt
,DATEDIFF(D, ROW_NUMBER() OVER(ORDER BY dt), dt) AS dt_range
FROM dt_list
Then use MIN() and MAX() to get the ranges:
WITH cal AS (SELECT CAST('2014-07-01' AS DATE) dt
UNION ALL
SELECT DATEADD(DAY,1,dt)
FROM cal
WHERE dt < '2014-07-30')
,dt_list AS (SELECT DISTINCT cal.dt
FROM cal
LEFT JOIN YourTable a
ON cal.dt BETWEEN CAST(SS_StartDate AS DATE) AND CAST(SS_EndDate AS DATE)
WHERE a.SS_StartDate IS NULL)
,dt_range AS (SELECT dt
,DATEDIFF(D, ROW_NUMBER() OVER(ORDER BY dt), dt) AS dt_range
FROM dt_list)
SELECT MIN(dt) AS BeginRange
,MAX(dt) AS EndRange
FROM dt_range
GROUP BY dt_range;
--OPTION (MAXRECURSION 0)
Demo: SQL Fiddle
Note: If the range you're checking is more than 100 days you'll need to specify the MAXRECURSION, 0 means no limit.
Note2: If your SE dates are intended to drive the complete date range, then change the cal cte from fixed dates to queries using MIN() and MAX() respectively.
A missing range must start at either se_StartDate or ss_EndDate+1. Likewise, it must end on either se_EndDate or ss_StartDate-1. Permute the candidate ranges and discard the overlappers.
The advantage of this method is that the time precision is easily adjustable to hours, or minutes or seconds without needing to enumerate every clock tick.
SQL Fiddle Demo
SELECT DISTINCT
range_start, range_end, se_StartDate, se_EndDate
FROM MyTable t1
CROSS APPLY (
SELECT se_StartDate range_start
UNION ALL
SELECT DATEADD(day,1,SS_EndDate)
) rs
CROSS APPLY (
SELECT se_EndDate range_end
UNION ALL
SELECT DATEADD(day,-1,SS_StartDate)
FROM MyTable
WHERE
se_StartDate = t1.se_StartDate AND
se_EndDate = t1.se_EndDate AND
SS_StartDate > range_start
) re
WHERE NOT EXISTS (
SELECT 1
FROM MyTable
WHERE
range_start < SS_EndDate AND
range_end > SS_StartDate
)
I would like to retrieve records between September 1st 2013 to September 1st 2014
My current method gets the records from September 2014 to September 2015-
But it should be September 2013 to September 2014.
What I am doing wrong is it because i am getting DateTime.Now?
int thisYear = DateTime.Now.Year;
DateTime thisYearStart = new DateTime(thisYear, 9, 1);
DateTime thisYearEnd = thisYearStart.AddYears(1).AddTicks(-1);
command.Parameters.AddWithValue("#Date1", thisYearStart);
command.Parameters.AddWithValue("#Date2", thisYearEnd);
from this how do i select a distinct records?
WITH cte AS
(
SELECT ROW_NUMBER() OVER(ORDER BY ID, Name,SName, DOB) AS ROW, *
FROM TableName
WHERE Date > #Date1 And Date < #Date2
)
SELECT * FROM cte
WHERE ROW BETWEEN 1 AND 200
Please try to use the follwoing as your startDate and endDate.
DateTime startDate = new DateTime(DateTime.Now.Year-1,9,1);
DateTime endDate = new DateTime(DateTime.Now.Year,9,1);
command.Parameters.AddWithValue("#time", startDate);
command.Parameters.AddWithValue("#time2", endDate);
Try this one for distinct
WITH cte AS
(
SELECT DISTINCT ID, ROW_NUMBER() OVER(ORDER BY ID, Name,SName, DOB) AS ROW, *
FROM TableName
WHERE Date > #Date1 And Date < #Date2
)
SELECT * FROM cte
WHERE ROW BETWEEN 1 AND 200