I want to see all units sold like this
select [UnitsSold] from MyTable
But I also want to add another column showing only the UnitsSold from the last 30 days
How can do this:
MyTable.CreatedOn >= DATEADD(MONTH, -1, GETDATE())
but only for one column.
So basically I want to see on the same row all units sold and then units sold the past 30 days
You can use CASE statement inside your aggregate function, something like....
Select SUM([UnitsSold]) TotalSold
, SUM(CASE WHEN CreatedOn >= DATEADD(MONTH, -1, GETDATE())
THEN [UnitsSold] ELSE 0 END) SoldInLastMonth
FROM MyTable
Related
I am trying to select records from today and the same day of each week for the last 4 weeks.
Today (Tuesday)
Last Tuesday
The Tuesday before that
The Tuesday before that
I need this to be tied to current date because I am going to run this query every day so I don't want to use a between or something where I manually specify the date range.
Everything I have found or tried so far has pulled the last month of data but not the last 4 weeks of the same weekday.
select *
from table
where thedatecolumn >= DATEADD(mm, -1, GETDATE())
This works but pulls everything from the last month.
If today's date is 7/10/2019 I need
Data from 7/10/2019
Data from 7/3/2019
Data from 6/26/2019
Data from 6/19/2019
Every day I will run this query, so I need it to be dynamic based on the current date.
I believe you want to look back 21 days and then filter those dates that have the same day of week:
select * from table
where thedatecolumn >= DATEADD(DAY, -21, CAST(GETDATE() AS DATE))
and DATEPART(WEEKDAY, thedatecolumn) = DATEPART(WEEKDAY, GETDATE())
You Can try using a recursive cte which starts today and repeatedly substracts 7 days - so you ensure you always land on the same weekday. Following an example:
WITH cteFromToday AS(
SELECT 0 AS WeeksBack, GETDATE() AS MyDate
UNION ALL
SELECT WeeksBack + 1 AS WeeksBack, DATEADD(d, -7, MyDate) AS MyDate
FROM cteFromToday
)
SELECT TOP 5 *
FROM cteFromToday
OPTION ( MaxRecursion 0 );
This is quite simple. Substitute CURRENT_TIMESTAMP here for any given date.
SELECT CONVERT(DATE,CURRENT_TIMESTAMP) AS Today,
DATEADD(DAY,-7,CONVERT(DATE,CURRENT_TIMESTAMP)) AS LastWeek ,
DATEADD(DAY,-14,CONVERT(DATE,CURRENT_TIMESTAMP)) AS TwoWeeksAgo,
DATEADD(DAY,-21,CONVERT(DATE,CURRENT_TIMESTAMP)) AS ThreeWeeksAgo
SO, if you want to get data for a set of ranges for one entire day with those dates:
SELECT something
WHERE
datetimecolumn >= CONVERT(DATE,CURRENT_TIMESTAMP) AND datetimecolumn < DATEADD(DAY,1, CONVERT(DATE,CURRENT_TIMESTAMP)) -- Todays range,
OR datetimecolumn >= DATEADD(DAY,-7,CONVERT(DATE,CURRENT_TIMESTAMP)) AND datetimecolumn < DATEADD(DAY,1,DATEADD(DAY,-7,CONVERT(DATE,CURRENT_TIMESTAMP)))-- LastWeek ,
OR datetimecolumn >= DATEADD(DAY,-14,CONVERT(DATE,CURRENT_TIMESTAMP)) AND datetimecolumn < DATEADD(DAY,1,DATEADD(DAY,-14,CONVERT(DATE,CURRENT_TIMESTAMP)))-- TwoWeeksAgo,
OR datetimecolumn >= DATEADD(DAY,-21,CONVERT(DATE,CURRENT_TIMESTAMP)) AND datetimecolumn < DATEADD(DAY,1, DATEADD(DAY,-21,CONVERT(DATE,CURRENT_TIMESTAMP))) -- ThreeWeeksAgo
I'm writing a SQL query using a table. My requirement is that I need to generate two logical columns from one physical column with certain conditions. In SQL how to generate two logical columns in final result set?
I have so far tried using sub-queries to derive those logical columns. But that sub-query returns error when incorporate it as a column in main query.
Overall there are other tables which will be joined using SQL JOIN to derive respective columns.
Columns:
CarrierName NVARCHAR(10)
MonthDate DATETIME
Stage INT
Scenario:
In my SQL Server table there is a column called Stage of type int that contains values like 1, 2, 3, 4.
Now, I have two date criteria to apply on above column to derive two logical columns in final result set.
Criteria #1:
Get carriers from past 12 months and priors to past month end date and value of "CurrentStage" should be less than and derive "PriorStage"
Example:
Current month is: March 2019 (2019-03-25) or any given date
Past latest month end date would be: 2019-02-28
12 months prior to above past latest month would be:
From 2018-02-01 To 2019-01-31
Criteria #2:
Get Carriers from past latest month end date and derive "CurrentStage"
While writing two independent SQL SELECT statements I get my desired results.
My challenge is when I think them to integrate in one select statement.
I get this error:
Subquery returned more than 1 value. This is not permitted when the subquery follows =, !=, <, <= , >, >= or when the subquery is used as an expression
Code:
DECLARE #DATE DATETIME
SET #DATE = '2018-08-25';
--QUERY 1 - RECORDS WITH PREVIOUS MONTH END DATE
SELECT
T1.CarrierName AS 'Carrier_Number',
T1.Stage AS 'Monitoring_Stage–Current'
FROM
table1 T1
WHERE
T1.Stage IS NOT NULL AND
CONVERT(DATE, T1.MonthDate) = CONVERT(DATE, DATEADD(D, -(DAY(#DATE)), #DATE))
--QUERY 2 - RECORDS FROM PAST 12 MONTHS PRIOR PREVIOUS MONTH END DATE
SELECT
T2.CarrierName,
T2.Stage AS 'Monitoring_Stage–Prior'
FROM
table2 T2
WHERE
T2.Stage IS NOT NULL AND
CONVERT(DATE, T2.MonthDate) BETWEEN CONVERT(DATE, DATEADD(M, -12, DATEADD(D, -(DAY(#DATE)), #DATE)))
AND CONVERT(DATE, DATEADD(D, -(DAY(#DATE) + (DAY(DATEADD(D, -(DAY(#DATE)), #DATE)))), #DATE))
AND T2.Stage) > (SELECT DISTINCT MAX(m.Stage AS INT))
FROM table1 m
WHERE CONVERT(DATE, m.MonthDate) = CONVERT(DATE, DATEADD(D, -(DAY(#DATE)), #DATE))
AND T2.CarrierName = m.CarrierName)
My final expected result set should contain below columns.
Where CurrentStage value is less than PriorStage value.
Expected Results
CarrierName | CurrentStage | PriorStage
--------------+--------------+-------------
C11122 | 1 | 2
C32233 | 3 | 4
Actual Result
I am looking for alternatives. I.e. CTE, Union, temp table etc.
Something like:
SELECT
CarrierName,
Query 1 Result As 'CurrentStage',
Query 2 Result As 'PrioreStage'
FROM
table1
To improve this post, I am adding my response here. My resolution below for this posted question is still under evaluation hence not posting it as my final answer. But it really brought a light to my effort.
RESOLUTION:
SELECT
DISTINCT M.CarrierName, A.[CurrentStage], B.[PriorStage]
FROM
--QUERY 1 - RECORDS WITH CURRENT MONTH END DATE
(SELECT M.CarrierName, M.CarrierID
, Stage AS 'CurrentStage'
FROM table1 M
WHERE M.Stage IS NOT NULL AND
CONVERT(date, M.MonthDate) = CONVERT(date, DATEADD(D,-(DAY(#DATE)), #DATE))
)
A **inner join**
(
--QUERY 2 - RECORDS FROM PAST 12 MONTHS PRIOR CURRENT MONTH END DATE
SELECT M2.CarrierName, M2.CarrierID
, Stage AS 'PriorStage'
FROM table1 M2
WHERE M2.Stage IS NOT NULL AND
CONVERT(date, M2.MonthDate) BETWEEN CONVERT(date, DATEADD(M, -12, DATEADD(D,-(DAY(#DATE)), #DATE)))
AND CONVERT(date, DATEADD(D,-(DAY(#DATE)+(DAY(DATEADD(D,-(DAY(#DATE)), #DATE)))), #DATE))
AND M2.Stage > (SELECT DISTINCT max(m.Stage)
FROM table1 m
WHERE CONVERT(date, m.MonthDate) = CONVERT(date, DATEADD(D,-(DAY(#DATE)), #DATE)) AND
M2.CarrierName = m.CarrierName
)
) B on b.Carrier_Number = a.Carrier_Number
INNER JOIN table1 M ON A.CarrierID = M.CarrierID AND B.CarrierID = M.CarrierID
The following query (on MSSQL) gives a correct answer to the question : how many IPs were collected on a monthly basis.
I would like to know how can I get the count per every 60 days?
select MIN(rowdate) min_rowdate,
MAX(rowdate) max_rowdate,
count(distinct IP),
DATEPART(MONTH, rowdate) month_
from t_tbl tl (nolock)
where rowdate between '2015-01-01 00:00:00' and '2015-12-31 23:59:59'
group by DATEPART(MONTH, rowdate)
You can get it using DATEDIFF and some simple maths:
select MIN(rowdate) min_rowdate, MAX(rowdate) max_rowdate, count(distinct IP),
DATEDIFF(day, 0, rowdate) / 60 as day60
from t_tbl tl (nolock)
where rowdate >= '20150101' and rowdate < '20160101'
group by DATEDIFF(day, 0, rowdate) / 60
In this instance, it's using 1900-01-01 (what 0 gets converted to) as the start of the first 60 day period and all subsequent periods follow on from there.
If you want to use a different "fixed point" for the reporting periods, you'd put that in in place of 0 as the second parameter to DATEDIFF.
(I've also corrected your WHERE clause so that it doesn't exclude any events that happened during the last second of 2015, i.e. with a non-zero milliseconds value)
I need the number of records of last month. I used to use this approach so far:
select
count(ID)
from
table
where
col1 = 'somerule'
and
DateTimeOfInsert >= '20150901'
and
DateTimeOfInsert <= '20150930'
Now I'm about to atomate this task and therefore I have to pull the start and end dates of last month automatically. So here it is:
select
count(ID)
from
table
where
col1 = 'somerule'
and
DATEPART(m, DateTimeOfInsert) = DATEPART(m, DATEADD(m, -1, getdate()))
and
DATEPART(yyyy, DateTimeOfInsert) = DATEPART(yyyy, DATEADD(m, -1, getdate()))
My only issue is that at this very moment the first query returns 1073 and the second one 1124. So the question is obvious: what is the difference between them? Both should inlude the start and end date. I can't spot it.
This condition:
DateTimeOfInsert >= '20150901' and DateTimeOfInsert <= '20150930'
retrieves record that are between 2015-09-01 00:00:00.000 and 2015-09-30 00:00:00.000.
If DateTimeOfInsert is DATETIME, then this will return different result from your other condition.
The best way for this kind of queries is not to use BETWEEN but rather use
>= and <. In your case, you want to get records for the last month, so you want to use >= start of last month and < start of this month:
DateTimeOfInsert >= DATEADD(MONTH, DATEDIFF(MONTH, 0, GETDATE()) - 1, 0) -- Beginning of previous month
AND DATEADD(MONTH, DATEDIFF(MONTH, 0, GETDATE()), 0) -- Beginning of this month
The above condition also makes your query sargable.
For some common date routines, see this article.
The difference is in time component of datetime.
This:
DateTimeOfInsert >= '20150901' and DateTimeOfInsert <= '20150930'
will not select date like 20150930 15:30.
But this:
DATEPART(m, DateTimeOfInsert) = DATEPART(m, DATEADD(m, -1, getdate()))
will select it because you are checking for months and year part only. That`s why the second select returns more rows.
Both queries will return the same if you just change the first statement so that it will consider time component of last day of month:
DateTimeOfInsert >= '20150901' and DateTimeOfInsert < '20151001'
so I'm trying to make a query that includes a daily sum of the amount from the first instance the database starts collecting data to the last available instance of that date (database collects data every hour). And while I have done this, now I have to make it show a month to date and a year to date sum amount. I have tried various ways to come up with this but have had no luck. Below is the code that I believe is the closest I have gotten to achieve this. Can someone help me make my code work or suggest another way around this?
Select * from
(
SELECT Devices.DeviceDesc,
SUM(DeviceSummaryData.Amount) AS MTD,
Devices.Area,
MIN(DeviceSummaryData.StartDate) AS FirstOfStartDate,
MAX(DeviceSummaryData.EndDate) AS LastOfStartDate
FROM Devices INNER JOIN DeviceSummaryData ON Devices.DeviceID = DeviceSummaryData.DeviceID
WHERE (DeviceSummaryData.StartDate = MONTH(getdate())) AND (DeviceSummaryData.EndDate <= CAST(DATEADD(DAY, 1, GETDATE())
AS date))
GROUP BY Devices.DeviceDesc, Devices.Area, DATEPART(day, DeviceSummaryData.StartDate)
--
) q2
UNION ALL
SELECT * FROM (
SELECT Devices.DeviceDesc,
Sum(Amount) as Daily,
Devices.Area,
MIN(StartDate) as FirstDate,
MAX(DeviceSummaryData.EndDate) AS LastOfStartDate
FROM Devices INNER JOIN DeviceSummaryData ON Devices.DeviceID = DeviceSummaryData.DeviceID
WHERE (DeviceSummaryData.StartDate >= CAST(DATEADD(DAY, 0, GETDATE()) AS date)) AND (DeviceSummaryData.EndDate <= CAST(DATEADD(DAY, 1, getdate()) AS date))
GROUP BY Devices.Area,
Devices.DeviceDesc,
DATEPART(day, DeviceSummaryData.StartDate)
ORDER BY Devices.DeviceDesc
) q2
Another type of attempt I have tried would be this:
SELECT Devices.DeviceDesc,
Sum(case
when DeviceSummaryData.StartDate >= CAST(DATEADD(DAY, 0, getdate()) AS date)
THEN Amount
else 0
end) as Daily,
Sum(case
when Month(StartDate) = MONTH(getdate())
THEN Amount
else 0
end) as MTD,
Devices.Area,
MIN(StartDate) as FirstDate,
MAX(DeviceSummaryData.EndDate) AS LastOfStartDate
FROM Devices INNER JOIN DeviceSummaryData ON Devices.DeviceID = DeviceSummaryData.DeviceID
WHERE (DeviceSummaryData.StartDate >= CAST(DATEADD(DAY, 0, GETDATE()) AS date)) AND (DeviceSummaryData.EndDate <= CAST(DATEADD(DAY, 1, getdate()) AS date))
GROUP BY Devices.Area,
Devices.DeviceDesc,
DATEPART(day, DeviceSummaryData.StartDate)
ORDER BY Devices.DeviceDesc
I'm not the best with Case When's, but I saw somewhere that this is a possible way to do this. I'm not too concerned with the speed or efficiency, I just need it to generate the query to be able to get the data. Any help and Suggestions are greatly appreciated!
The second attempt is on the right track but a bit confused. In the CASE statements you are trying to compare months etc, but your WHERE clause restricts the data you're looking at to a single day. Also, your GROUP BY should not include the day anymore. If you say in English what you want, it's "For each device area and type, I want to see a total, a MTD total and a YTD total". It's that "For each" bit that should define what appears in your GROUP BY.
Just remove the WHERE clause entirely and get rid of DATEPART(day, DeviceSummaryData.StartDate) from your GROUP BY and you should get the results you want. (Well, a daily and monthly total, anyway. Yearly is achieved much the same way).
Also note that DATEADD(DAY, 0, GETDATE()) is identical to just GETDATE().