Update all date columns in SQL Server -1 day - sql

I want to update my database (SQL Server Express) all the dates for specific ids.
I am displaying the ids I want to.
SELECT TOP (1000) ID, Dates
FROM tbl_table
WHERE (id IN (29695, 29700, 29701, 29702, 29703, 29704, 29705, 29706, 29707, 29708, 29709, 29710, 29711, 29712, 29713, 29714, 29715))
AND my dates in the database are like this:
Is there any way to update all the date columns with same date - 1 day?
For example: if we have 2019-12-20, update it to 2019-12-19?
For example if I want to do it in PHP, I would loop through this query and fetch all all dates. After I would remove one day like this:
date('m/d/Y', strtotime($date. ' - 1 days');
And create a query to update all the columns based on id. I just want to avoid that. Is there any SQL command that do that?
Thanks

The request below will update the rows you want by adding -1 days on each date:
UPDATE tbl_table
SET dates = Dateadd(day, -1, dates)
WHERE id IN ( 29695, 29700, 29701, 29702,
29703, 29704, 29705, 29706,
29707, 29708, 29709, 29710,
29711, 29712, 29713, 29714, 29715 )
DATEADD function takes 3 parameters:
the interval ( day, month, year ..)
the increment (the value to add or remove if negative)
an expression (wich is a datetime type)
See DATEADD documentation

To return a query with the previous day:
SELECT TOP (1000) ID, Dates, DATEADD(dd, -1, Dates) AS PreviousDay
FROM tbl_table
To update the table with the previous day:
UPDATE tbl_table
SET Dates = DATEADD(dd, -1, Dates)
FROM -- Put your conditions here

UPDATE tableName SET date= DATEADD(d,-1, date)
where ....
( here you put where clause for you required)

Related

Expanding SQL query for multiple dates

I have a SQL query that includes a __DATE__ macro. A Python script replaces this macro with the current date and then the statement is executed thus giving one day's worth of data.
For the first item selected, I would like to use tblLabTestResult.CollectionDate instead of __DATE__.
I would like to include the prior 7 days instead of just the current day.
The desired output would be something similar to:
Date,Result,Total
2021-08-28,Detected,5
2021-08-28,Not Detected,9
2021-08-29,Detected,23
2021-08-29,Not Detected,6
2021-08-30,Detected,88
2021-08-30,Not Detected,26
Current query:
SELECT
'__DATE__' as Date,
tblLabTestResult.Result as Result,
Count(tblLabTestResult.Result) as Total
FROM
PncRegDb.dbo.tblLabTestResult as tblLabTestResult
WHERE
tblLabTestResult.TestName like '%cov%'
AND tblLabTestResult.TestName not like '%aoe%'
AND tblLabTestResult.TestName not like '%antibody%'
AND tblLabTestResult.CollectionDate >= '__DATE__'
AND tblLabTestResult.CollectionDate <= '__DATE__ 11:59:59 PM'
GROUP BY
tblLabTestResult.Result;
How can I change my SQL query to accommodate these requirements? I am using MS SQL Server.
You can use DATEADD() function to get the date from 7 days ago and use all dates between date-7days and date. I have updated where condition in your query below:
SELECT
'__DATE__' as Date,
tblLabTestResult.Result as Result,
Count(tblLabTestResult.Result) as Total
FROM
PncRegDb.dbo.tblLabTestResult as tblLabTestResult
WHERE
tblLabTestResult.TestName like '%cov%'
AND tblLabTestResult.TestName not like '%aoe%'
AND tblLabTestResult.TestName not like '%antibody%'
AND tblLabTestResult.CollectionDate between DATEADD(day, -7, '__DATE__') and '__DATE__ 11:59:59 PM'
GROUP BY
tblLabTestResult.Result;
A few points:
Columns that are not aggregated must be in the GROUP BY
You should be passing your date as a parameter
Best to use a half-open interval to compare dates (exclusive end-point), so #endDate is the day after the one you want
Use short, meaningful aliases to make your code more readable
It doesn't make sense to group and aggregate by the same column. If Result is a non-nullable column then Count(Result) is the same as Count(*)
If you want to group by whole days (and CollectionDate has a time component) then replace ltr.CollectionDate with CAST(ltr.CollectionDate AS date) in both the SELECT and GROUP BY
SELECT
ltr.CollectionDate as Date,
ltr.Result as Result,
COUNT(*) as Total
FROM
PncRegDb.dbo.tblLabTestResult as tblLabTestResult
WHERE
ltr.TestName like '%cov%'
AND ltr.TestName not like '%aoe%'
AND ltr.TestName not like '%antibody%'
AND ltr.CollectionDate >= #startdate
AND ltr.CollectionDate < #endDate
GROUP BY
ltr.CollectionDate, ltr.Result;

sql save row count of query every day

I want to create a view or table that counts eg. total number of students on that day the query is executed and add row results each day. Problem is the date column on table changes everyday to the current date.
SELECT
COUNT(*) AS no_of_Students
,CAST(GETDATE() AS DATE) as DATE
FROM mySchool
WHERE students=1
No of student . Date
-----------------------
8 . 2019.02.06
15 . 2019.02.07
(next row should auto update for next day when running the query)
You should not be using GETDATE(), You need to pick the date column you have in your mySchool table.
You need to write your query like following.
SELECT
COUNT(*) as [no_of_Students]
,CAST([DateCoulumn] AS DATE) as [DATE]
FROM [mySchool]
GROUP BY CAST(DateCoulumn AS DATE)
ORDER BY CAST(DateCoulumn AS DATE)
Note: You need to replace DateCoulumn with the correct column name.

SQL Server : average count of alerts per day, not including days with no alerts

I have a table that acts as a message log, with the two key tables being TIMESTAMP and TEXT. I'm working on a query that grabs all alerts (from TEXT) for the past 30 days (based on TIMESTAMP) and gives a daily average for those alerts.
Here is the query so far:
--goback 30 days start at midnight
declare #olderdate as datetime
set #olderdate = DATEADD(Day, -30, DATEDIFF(Day, 0, GetDate()))
--today at 11:59pm
declare #today as datetime
set #today = dateadd(ms, -3, (dateadd(day, +1, convert(varchar, GETDATE(), 101))))
print #today
--Grab average alerts per day over 30 days
select
avg(x.Alerts * 1.0 / 30)
from
(select count(*) as Alerts
from MESSAGE_LOG
where text like 'The process%'
and text like '%has alerted%'
and TIMESTAMP between #olderdate and #today) X
However, I want to add something that checks whether there were any alerts for a day and, if there are no alerts for that day, doesn't include it in the average. For example, if there are 90 alerts for a month but they're all in one day, I wouldn't want the average to be 3 alerts per day since that's clearly misleading.
Is there a way I can incorporate this into my query? I've searched for other solutions to this but haven't been able to get any to work.
This isn't written for your query, as I don't have any DDL or sample data, thus I'm going to provide a very simple example instead of how you would do this.
USE Sandbox;
GO
CREATE TABLE dbo.AlertMessage (ID int IDENTITY(1,1),
AlertDate date);
INSERT INTO dbo.AlertMessage (AlertDate)
VALUES('20190101'),('20190101'),('20190105'),('20190110'),('20190115'),('20190115'),('20190115');
GO
--Use a CTE to count per day:
WITH Tots AS (
SELECT AlertDate,
COUNT(ID) AS Alerts
FROM dbo.AlertMessage
GROUP BY AlertDate)
--Now the average
SELECT AVG(Alerts*1.0) AS DayAverage
FROM Tots;
GO
--Clean up
DROP TABLE dbo.AlertMessage;
You're trying to compute a double-aggregate: The average of daily totals.
Without using a CTE, you can try this as well, which is generalized a bit more to work for multiple months.
--get a list of events per day
DECLARE #Event TABLE
(
ID INT NOT NULL IDENTITY(1, 1)
,DateLocalTz DATE NOT NULL--make sure to handle time zones
,YearLocalTz AS DATEPART(YEAR, DateLocalTz) PERSISTED
,MonthLocalTz AS DATEPART(MONTH, DateLocalTz) PERSISTED
)
/*
INSERT INTO #Event(EntryDateLocalTz)
SELECT DISTINCT CONVERT(DATE, TIMESTAMP)--presumed to be in your local time zone because you did not specify
FROM dbo.MESSAGE_LOG
WHERE UPPER([TEXT]) LIKE 'THE PROCESS%' AND UPPER([TEXT]) LIKE '%HAS ALERTED%'--case insenitive
*/
INSERT INTO #Event(DateLocalTz)
VALUES ('2018-12-31'), ('2019-01-01'), ('2019-01-01'), ('2019-01-01'), ('2019-01-12'), ('2019-01-13')
--get average number of alerts per alerting day each month
-- (this will not return months with no alerts,
-- use a LEFT OUTER JOIN against a month list table if you need to include uneventful months)
SELECT
YearLocalTz
,MonthLocalTz
,AvgAlertsOfAlertingDays = AVG(CONVERT(REAL, NumDailyAlerts))
FROM
(
SELECT
YearLocalTz
,MonthLocalTz
,DateLocalTz
,NumDailyAlerts = COUNT(*)
FROM #Event
GROUP BY YearLocalTz, MonthLocalTz, DateLocalTz
) AS X
GROUP BY YearLocalTz, MonthLocalTz
ORDER BY YearLocalTz ASC, MonthLocalTz ASC
Some things to note in my code:
I use PERSISTED columns to get the month and year date parts (because I'm lazy when populating tables)
Use explicit CONVERT to escape integer math that rounds down decimals. Multiplying by 1.0 is a less-readable hack.
Use CONVERT(DATE, ...) to round down to midnight instead of converting back and forth between strings
Do case-insensitive string searching by making everything uppercase (or lowercase, your preference)
Don't subtract 3 milliseconds to get the very last moment before midnight. Change your semantics to interpret the end of a time range as exclusive, instead of dealing with the precision of your datatypes. The only difference is using explicit comparators (i.e. use < instead of <=). Also, DATETIME resolution is 1/300th of a second, not 3 milliseconds.
Avoid using built-in keywords as column names (i.e. "TEXT"). If you do, wrap them in square brackets to avoid ambiguity.
Instead of dividing by 30 to get the average, divide by the count of distinct days in your results.
select
avg(x.Alerts * 1.0 / x.dd)
from
(select count(*) as Alerts, count(distinct CAST([TIMESTAMP] AS date)) AS dd
...

How can I use DATEPART to return all rows with a specific year

My database has a table 'Events'. Columns include 'name', 'Date' and 'Type
I want to run a query that returns all the event names of a given date AND type.
Firstly, how can I use the DATEPART to break up the date and allow it to be identified by the year.
Assuming you're using SQL Server and that your 'Date' column is DATE or DATETIME data type, you can do this:
SELECT GETDATE() -- i.e. will return 2015-11-25 11:27:27.700
SELECT DATEPART(YEAR,GETDATE()) -- returns 2015
So your query to get all events in 2015 for example, could look like this:
SELECT Name, Date, Type
FROM Events
WHERE DATEPART(YEAR,Date) = 2015
AND TYPE = <your type condition>
ORDER BY Date;
If you use the 'datepart' function, this will be called for every row in your database, which can be costly.
It's better to select the year by using a range, then it can use indexes to search for the relevant rows in your database.
select * from Events where [Date]>='1 jan 2015' and [Date]<'1 jan 2016' and [type]=1

Select from table given day

So I have a table in SQL Server with a datetime column on it. I want to select all from this table:
select * from dbo.tblMessages
but I want to pass in a datetime parameter. Then I want to select all messages from the table that have the same day as the datetime column in tblMessages, not just ones posted in the past 24 hours, etc.
How would I do this?
Thanks.
This should use an index on MyDateTimeCol in tblMessages
select * from dbo.tblMessages
WHERE
MyDateTimeCol >= DATEADD(day, DATEDIFF(day, 0, #Mydatetimeparameter), 0)
AND
MyDateTimeCol < DATEADD(day, DATEDIFF(day, 0, #Mydatetimeparameter), 1)
Any function applied to MyDateTimeCol will prevent an index being used correctly, includin DATEDIFF between this and #Mydatetime
As you are on SQL Server 2008 you can just do
SELECT *
FROM tblMessages
WHERE CAST(message_date AS DATE) = CAST(#YourDateParameter AS DATE)
This is sargable. SQL Server will add a ComputeScalar to the plan that calls the internal GetRangeThroughConvert function and gets the start and end of the range to seek.
If you need to do this a lot, and if you're on SQL Server 2005 or newer, you could also do this:
add three computed columns for the day, month, year of your date and persist those
ALTER TABLE dbo.YourTable
ADD DayPortion AS DAY(YourDateTimeColumn) PERSISTED
-- do the same for MONTH(YourDateTimeColumn) and YEAR(YourDateTimeColumn)
put an index on the three columns:
CREATE NONCLUSTERED INDEX IX_DatePortions
ON dbo.tblMessages(YearPortion, MonthPortion, DayPortion)
now, you can search very easily and quickly for those days, months, year, and with the index, your search will be very performant and quick
SELECT (list of columns)
FROM dbo.tblMessages
WHERE YearPortion = 2011 AND MonthPortion = 4 AND DayPortion = 17
With this setup - three computed, persisted columns - you can now simply insert new rows into the table - those three columns will be calculated automatically.
Since they're persisted and indexed, you can easily and very efficiently search on those columns, too.
And with this flexibility, you can also easily find e.g. all rows for a given month or year very nicely.