I want to write a function / stored procedure where I want to pass a date and time and get all the rows that exist for a particular date and time, if records were deleted after that date and time it should show them otherwise no.
Let's say I have a table students (id, name, createdate) with 100 rows today morning before 10:30 am, I delete 30 records today at 10:30 am and I run my function with today's date and time 10:35, it should return 70 records, but if I run the function with an older date like today's date at 09:30 am, it should return 100 records.
Please reply with the best possible solutions for this in SQL Server. I don't want to create a separate table of deleted items and then compare and show with that.
DELETE removes the rows, they are not available to view later on.
Unless you are using Sql Server 2016+ and then you could use a System versioned temporal table.
You could create an IsActive column or something to that effect, and instead of DELETE you UPDATE tbl SET IsActive = 0, dateInactivated = getdate() WHERE...
Then in your stored procedure you would:
SELECT *
FROM tbl
WHERE IsActive = 1
OR (IsActive = 0 AND dateInactivated > #myDate)
(EDIT reason: helpful comments below)
Related
I am trying to write sql query for the following scenario. It would be great if can get any help on it.
Scenario :
I have a table(emp) which has three columns id,time and value. There is no primary key in the table. time is a date column holding date and timestamp.
Table will be started to update from afternoon onwards. So table will have yesterday data in it from morning to afternoon. Before inserting current data in it all the yesterday's rows will be cleared and table will be start to be updated dynamically from noon till evening .But I need to run the query running from morning onwards and my query should not fetch yesterday's data. So from morning to afternoon I should ideally wait for data to come and should not fetch any rows and start to fetch once the current date data was inserted into it.
I need to run the query for every five minutes and when I run the query I should get all the latest rows in the table so that whenever there is a update in the table those rows will be fetched .
For example when the table is updated from 1 PM onwards. I should get all the rows when i start the first query and after five minutes when i once again run the same query at 1.05 i should get all the rows inserted between 1PM and 1.05PM.
My idea :
Select max(time) from emp;
At the start of the day I should check the max time in the table and it will be definitely yesterday date so I will set today date(2018-07-14 00:00:00) in a local variable or if it's today's date then that value will be stored in the local variable.
I can also do the same in the above query by comparing it with sysdate like below query but not sure about the performance as I saw it took time by comparing with all the rows I guess. See the modified above query below
select max(time) from emp where time = sysdate;
After getting the max time from the table , will have it one variable say lastquerytime, then query the table which has rows greater than this time stamp so that we can fetch all the latest rows for every five minutes.
Select id,time,value from emp where time > lastquerytime;
So the idea is getting all the rows and check the maximum timestamp in it and query the table next time with rows having timestamp greater than this max timestamp. Like this need to do the same for every five minutes till the end of the day.
Now I am using two queries to achieve this scenario.
Any suggestions for better approach and queries to write for this scenario will help me a lot.
You should use something like to get data from yesterday:
SELECT id,time,value FROM emp WHERE time BETWEEN TRUNC(SYSDATE - 1) AND TRUNC(SYSDATE) - 1/86400
If I understand correctly, you want all rows on the maximum date of the table.
If so:
select e.*
from emp
where time >= (select trunc(max(time)) from emp);
If you want the results based on clock-time, then you would use trunc(sysdate) instead.
We have a SQL Server database for storing our transaction data. In each of the table, we have a LastUpdatedOn column which gets populated by using the GETDATE() function.
What we are seeing is when we have bulk update operations on these tables, at the end of bulk operation, the timestamp in the LastUpdatedOn column will be past date.
Eg: if the update operation started at time 10:00:00.000 AM, the GETDATE() function will select that as the time and the LastUpdatedOn column will be populated with datetime as 10:00:00.000 AM. If the script takes 30 seconds to execute, the at 10:00:30.000 AM, when the scripts completes the executed, the lastupdateon column will be populated with a past date.
See the sample script below:
SELECT TOP 100000 *
INTO #tmp
FROM dbo.Test
BEGIN TRAN
UPDATE L
SET l.lastupdateon = getdate()
FROM dbo.Test L
JOIN #tmp T ON T.entitykey = L.entitykey
COMMIT TRAN
The issue which we are running into is, we have a delta operation that has from and to dates. This operation will return any records that got updated between the from and to date. In this case, if delta operation gets called at 10:00:15.000 AM, the records that got updated as a part of the script will not be pulled even though the record got updated at 10:00:00.000 AM. These records will never get pulled.
Is there any solution for this problem other than making the transaction serializable?
Regards,
John
The fundamental problem is that the update takes time, so there will always be a delay between when you tell SQL Server to write a value to the table and when that value is committed and visible to others.
You need to address this in your delta operation. Is only one process writing to the table? If so, newly committed rows will always have a LastUpdatedOn value that is after everything else in the table. In this case, the delta operation should keep track of the max LastUpdatedOn value it got last time and look for anything greater than that.
I'd like to know if is it possible to trigger a delete on a table, if a date of a row is less than current date?
For example
ID token Expiration_date
---------------------------
1 fkjeorf 2017/05/15 14:05:00
2 gdgrhjj 2017/05/16 13:05:00
3 mojkkut 2017/05/17 18:05:00
If we are on the 2017/05/17 18:00:00, then the two first rows are auto deleted
You can set up a job to delete the records (using SQL Server Agent).
I would recommend that you simply use a view so the data is always accurate:
create view v_example_actives as
select e.*
from example e
where expiration_date < getdate();
Personally, I prefer to keep all the rows in the table (for future analysis). But, you can periodically delete rows at a convenient time. Users of the view will never see expired accounts.
I'm trying to query my SQL Server 2008 R2 database to find out records that were put into a cancelled state during a given time period. Each record consist of one row in the database with a Created By timestamp, and a modified by timestamp. I can't change the schema of the database.
Each record has a "cancel state" column that is set to 0 or 1 (N and Y). I need to run a nightly job/query that will show all of the cancelled records from the day.
Simple enough, when the record is cancelled the modified timestamp is updated, so my query looks like
SELECT *
FROM mytable
WHERE CONVERT(DATE, a.modified_timestamp) = CONVERT(DATE, CURRENT_TIMESTAMP)
AND cancel_flag = '1'
The issue I am running into, if any other data is modified in the record, the timestamp is updated so the query will give me duplicate results if some other value in the row is changed. Is there an easy way to do this without changing the schema or adding my own table for tracking?
I'm trying to generate monthly records in one table based on instructions in another table. Software - MS Access 2007, though I'm looking for an SQL solution here. To greatly simplify the matter, let's say the following describes the tables:
TaskManager:
- DayDue
- TaskName
Task:
- DateDue
- TaskName
So what happens is that there may be an entry in TaskManager {15, "Accounts due"}, so this should lead to an "Account due" record in the Task table with the due date being the 15th of each month. I'd want it to create records for the last few months and the next year.
What I'm thinking that I need to do is first create a SELECT query that results in x records for each record in the TaskManager table, with a date for each month. After that, I do an INSERT query which inserts records into the Task table if they do not EXIST in the aforementioned SELECT query.
I think I can manage the INSERT query, though I'm having trouble figuring out how to do the SELECT query. Could someone give me a pointer?
You could use a calendar table.
INSERT INTO Task ( DateDue, TaskName )
SELECT calendar.CalDate, TaskManager.TaskName
FROM calendar, TaskManager
WHERE (((Day([CalDate]))=TaskManager.DayDue)
AND ((calendar.CalDate)<#7/1/2013#));
The calendar table would simply contain all dates and other such relevant fields as work day (yesno). Calendar tables are generally quite useful.
Here is the solution I developed using Remou's Calendar table idea.
First create a Calendar table, which simply contains all dates for a desired range. It's easy to just make the dates in Excel and paste them into the table. This is also a very reliable way of doing it, as Excel handles leap years correctly for the modern range of dates.
After building this table, there are three queries to run. The first is a SELECT, which selects every possible task generated by the TaskManager based on the date and frequency. This query is called TaskManagerQryAllOptions, and has the following code:
SELECT TaskManager.ID, Calendar.CalendarDate
FROM TaskManager INNER JOIN Calendar ON
TaskManager.DateDay = Day(Calendar.CalendarDate)
WHERE (TaskManager.Frequency = "Monthly")
OR (TaskManager.Frequency = "Yearly" AND
TaskManager.DateMonth = Month(Calendar.CalendarDate))
OR (TaskManager.Frequency = "Quarterly" AND
(((Month(Calendar.CalendarDate)- TaskManager.DateMonth) Mod 3) = 0));
The bulk of the above is to cover the different options a quarterly Day and Month pair could cover. The next step is another SELECT query, which selects records from the TaskManagerQryAllOptions in which the date is within the required range. This query is called TaskManagerQrySelect.
SELECT TaskManagerQryAllOptions.ID, TaskManager.TaskName,
TaskManagerQryAllOptions.CalendarDate
FROM TaskManagerQryAllOptions INNER JOIN TaskManager
ON TaskManagerQryAllOptions.ID = TaskManager.ID
WHERE (TaskManagerQryAllOptions.CalendarDate > Date()-60)
AND (TaskManagerQryAllOptions.CalendarDate < Date()+370)
AND (TaskManagerQryAllOptions.CalendarDate >= TaskManager.Start)
AND ((TaskManagerQryAllOptions.CalendarDate <= TaskManager.Finish)
OR (TaskManager.Finish Is Null))
ORDER BY TaskManagerQryAllOptions.CalendarDate;
The final query is an INSERT. As we will be using this query frequently, we don't want it to generate duplicates, so we need to filter out already created records.
INSERT INTO Task ( TaskName, TaskDate )
SELECT TaskManagerQrySelect.TaskName, TaskManagerQrySelect.CalendarDate
FROM TaskManagerQrySelect
WHERE Not Exists(
SELECT *
FROM Task
WHERE Task.TaskName = TaskManagerQrySelect.TaskName
AND Task.TaskDate = TaskManagerQrySelect.CalendarDate);
One limitation of this method is that if the date of repetition (e.g. the 15th of each month) is changed, the future records with the wrong day will remain. A solution to this would be to update all the future records with the adjusted date, then run the insert.
One possibility could be to create a table of Months, and a table of Years (prior year, current, and next one). I could run a SELECT query which takes the Day from the TaskManager table, the Month from the Month table, and the Year from the Year table - I imagine that this could somehow create my desired multiple records for a single TaskManager record. Though I'm not sure what the exact SQL would be.