SQL Server row date last modified
As the others are hinting at, your colleague must be talking gibberish, or referring to something else. The on-disk structure for a record, or page for that sake, does not contain any references to the time of the last update. While you can find info regarding the last update at the object level, no such info is available at the record/row level.
Select the row with the most recent modified date
you can go for row_number() with partition by
Schema (PostgreSQL v10.0)
create table users(user_id integer, name varchar(10), email varchar(20), modified_date timestamp);
insert into users
values
(1 ,'John', 'a@gmail.com', '2022-01-01'),
(1 ,'John', 'b@gamil.com', '2022-02-01');
Query #1
select user_id, email, name
from
(
SELECT user_id, name, email,row_number() over(partition by user_id order by modified_Date desc) as rnk
FROM users
) as t
where rnk = 1;
user_id | name | |
---|---|---|
1 | b@gamil.com | John |
How do I add a “last modified” and created column in a SQL Server table?
The created
column is simple - just a DATETIME2(3)
column with a default constraint that gets set when a new row is inserted:
Created DATETIME2(3)
CONSTRAINT DF_YourTable_Created DEFAULT (SYSDATETIME())
So when you insert a row into YourTable
and don't specify a value for Created
, it will be set to the current date & time.
The modified
is a bit more work, since you'll need to write a trigger for the AFTER UPDATE
case and update it - you cannot declaratively tell SQL Server to do this for you....
Modified DATETIME2(3)
and then
CREATE TRIGGER updateModified
ON dbo.YourTable
AFTER UPDATE
AS
UPDATE dbo.YourTable
SET modified = SYSDATETIME()
FROM Inserted i
WHERE dbo.YourTable.PrimaryKey = i.PrimaryKey
You need to join the Inserted
pseudo table which contains all rows that were updated with your base table on your primary key for that table.
And you'll have to create this AFTER UPDATE
trigger for each table that you want to have a modified
column in.
SQL Server database last updated date time
Look in sys.objects should be enough, try this query
select * from sys.objects
order by modify_date desc
Find the last time table was updated
If you're talking about last time the table was updated in terms of its structured has changed (new column added, column changed etc.) - use this query:
SELECT name, [modify_date] FROM sys.tables
If you're talking about DML operations (insert, update, delete), then you either need to persist what that DMV gives you on a regular basis, or you need to create triggers on all tables to record that "last modified" date - or check out features like Change Data Capture in SQL Server 2008 and newer.
Select only rows with last modified timestamp, without duplicate rows with same ID and older timestamp
with x as (select o.modified, od.*
from orderDetails od, orders o
where o.id=od.order_id)
, mx as (select max(modified) as modified, detail_id
from x group by detail_id)
Select x.* from x, mx
Where x.detail_id = mx.detail_id and x.modified=mx.modified
Here we use Common Table Expressions, so we join the two tables only once.
At least we did it only once when writing the query - thus we would have less chances to do typo or copy-paste errors.
We also hinted the SQL server to do the join only once and then to reuse it, but would it follow this hint or not - depends on its internal implementation.
Another good thing about CTE: it helps you to build your query incrementally, step by step, from simple to complex. Read about Read–eval–print loop at https://en.wikipedia.org/wiki/REPL
I would add a bit more of it later.
You can find many articles about CTE in Google. The Firebird implementation is documented here: https://www.firebirdsql.org/file/documentation/reference_manuals/fblangref25-en/html/fblangref25-dml-select.html#fblangref25-dml-select-cte
Since I used only very basic SQL I believe it to work in almost any practical SQL server, Firebird including.
Here is the result of the query and the output data: SQL Fiddle
PostgreSQL 9.6 Schema Setup:
create table orders
(id integer primary key,
modified timestamp);
create index o_m on orders(modified);
create table OrderDetails(
order_id integer references orders(id),
detail_id integer not null,
base_price float,
buy_price float,
sell_price float );
create index od_do on OrderDetails(detail_id, order_id);
Insert into orders values
( 1, '2018-1-07'),
( 2, '2018-1-10'),
( 3, '2018-1-15'),
( 4, '2018-1-20'),
( 5, '2018-1-25');
Insert into OrderDetails values
( 1 , 1 , 99.00 , 111.00 , 122.00 ),
( 1 , 2 , 82.00 , 95.00 , 117.00 ),
( 1 , 3 , 82.00 , 95.00 , 117.00 ),
( 2 , 4 , 95.00 , 108.00 , 119.00 ),
( 2 , 5 , 86.00 , 94.00 , 115.00 ),
( 2 , 1 , 82.00 , 95.00 , 117.00 ),
( 3 , 1 , 92.00 , 106.00 , 116.00 ),
( 3 , 4 , 90.00 , 100.00 , 120.00 ),
( 3 , 5 , 82.00 , 95.00 , 117.00 ),
( 4 , 2 , 92.00 , 106.00 , 116.00 ),
( 4 , 3 , 90.00 , 100.00 , 120.00 ),
( 4 , 1 , 82.00 , 95.00 , 117.00 ),
( 5 , 1 , 92.00 , 106.00 , 116.00 ),
( 5 , 5 , 90.00 , 100.00 , 120.00 ),
( 5 , 3 , 82.00 , 95.00 , 117.00 );
Query 1:
with x as (select o.modified, od.*
from orderDetails od, orders o
where o.id=od.order_id)
, mx as (select max(modified) as modified, detail_id
from x group by detail_id)
Select x.* from x, mx
Where x.detail_id = mx.detail_id and x.modified=mx.modified
Order by detail_id
Results:
| modified | order_id | detail_id | base_price | buy_price | sell_price |
|----------------------|----------|-----------|------------|-----------|------------|
| 2018-01-25T00:00:00Z | 5 | 1 | 92 | 106 | 116 |
| 2018-01-20T00:00:00Z | 4 | 2 | 92 | 106 | 116 |
| 2018-01-25T00:00:00Z | 5 | 3 | 82 | 95 | 117 |
| 2018-01-15T00:00:00Z | 3 | 4 | 90 | 100 | 120 |
| 2018-01-25T00:00:00Z | 5 | 5 | 90 | 100 | 120 |
Note, it would have different output if you would have two or more orders with the same timestamp! It seems you did not even thought about this possibility - but since it is possible, it would eventually happen.
Now, Back to CTE and REPL.
As you incrementally build your query, from the first vague idea to specific rows, it would be nice to check that the output data is exactly what you expect. "Big elephant it better to be eaten by small pieces".
And here I will show you the step by step building of the query.
It would be useful if you would repeat those steps in the SQL Fiddle linked above.
First of all I created and populated the tables.
Then I issued the first queries just to check I did populated them correctly.
1: select * from orders
- try this and further queries in SQL fiddle (or in IBExpert, FlameRobin, etc
2: select * from orderDetails
3: Then I issued the joining query to check if my cross-tables query really gives meaningful output. It did.
select o.modified, od.*
from orderDetails od, orders o
where o.id=od.order_id
4: Then I wondered, can I get the last timestamp for detail out of that query? To check it what I did was the following: 1) saved the aforementioned query I did and tested earlier, and 2) wrote a secondary query on top of it. It did extracting the last change date okay. Written and tested.
with x as (select o.modified, od.*
from orderDetails od, orders o
where o.id=od.order_id)
Select max(modified) as modified, detail_id
from x group by detail_id
5: And the last step was saving the test secondary query too, and writing the final, tertiary query on top of them both, giving the final filtered data
Yet more efficient solution can be using the one-run join query (the one I introduced above in Step 3. and saved as x
) with adding order by detail_id, modified desc
and then using Window Functions introduced in Firebird 3.
Here is the answer to a similar question using that approach - Firebird select from table distinct one field
Window Functions are not available in Firebird 2.x though.
Optimized SQL query for getting last modified date of a user information
If I understood the question correctly, you want the latest modification date for each user. Which boils down to a greatest-n-per-group problem (with n=1). And they are typically solved using distinct on ()
in Postgres:
select distinct on (usr.id) id, last_modified_date
from
(
select id, last_modified_date
from "User_Details"
UNION ALL
select user_id as id, last_modified_date
from "User_Contact_Details"
UNION ALL
select user_id as id, last_modified_date
from "User_Social_Media_Details"
) as usr
where last_modified_date is not null
order by id, last_modified_date desc;
The order by
inside the union queries is not really necessary, unless you want to pre-filter the user IDs in there already, which might be more efficient:
select distinct on (usr.id) id, last_modified_date
from
(
select distinct on (id) id, last_modified_date
from "User_Details"
order by id, last_modified_date desc
UNION ALL
select distinct on (user_id) user_id as id, last_modified_date
from "User_Contact_Details"
order by user_id, last_modified_date desc
UNION ALL
select distinct on (user_id) user_id as id, last_modified_date
from "User_Social_Media_Details"
order by user_id, last_modified_date desc
) as usr
where last_modified_date is not null
order by id, last_modified_date desc;
You still need the distinct on ()
in the outer query because the same user ID could be returned from the different branches of the UNION.
user
is a reserved keyword, avoid using it as an identifier. And if you do, you have to quote it "user"
to avoid confusion with the built-in function user
If the "User_Details"
table is the "master" table, referenced by the others and you just want to get the latest modification date per user id, regardless in which table that occurred, you could also use a join with a group by:
select id,
max(greatest(ud.last_modified_date, ucd.last_modified_date, usmd.last_modified_date)) as latest_modification
from "User_Details" ud
left join "User_Contact_Details" ucd on ucd.user_ud = ud.id
left join "User_Social_Media_Details" usmd on usmd.user_id = ud.id
group by id;
Date object last modified
Note that SQL Server actually does not record the last modification date. It does not exist in any system tables.
The Schema Changes History report is actually constructed from the Default Trace. Since many admins (and web hosts) turn that off, it may not work for you.
Buck Woody had a good explanation of how this report works here. The data is also temporary.
For this reason, you should never RELY on the Schema Changes History report. Alternatives:
- Use DDL Triggers to log all schema modification to a table of your choosing.
- Enforce a protocol where views and procs are never altered, they are only dropped and recreated. This means the created date will also be the last updated date (this does not work with tables obviously).
- Vigilantly version your SQL objects and schema in source control.
--
Edit: saw that this is SQL 2000. That rules out Default Trace and DDL Triggers. You're left with one of the more tedious options I listed above.
Getting the most recent Modified Date older than 7 days per record with multiple dates
Try adding a having clause
SELECT USERID
FROM [PROJ]
INNER JOIN [NOTES] ON [PROJ].id = [NOTES].projID
WHERE [PROJ.STATUS] = 'ACTIVE'
AND [NOTES.MODIFIEDDATE] <= GETDATE() - 7
GROUP BY USERID
HAVING MAX([NOTES.MODIFIEDDATE])
EDIT:
If you only want the most recent then I would get rid of the entirely
AND [NOTES.MODIFIEDDATE] <= GETDATE() - 7
SELECT USERID
FROM [PROJ]
INNER JOIN [NOTES] ON [PROJ].id = [NOTES].projID
WHERE [PROJ.STATUS] = 'ACTIVE'
GROUP BY USERID
HAVING MAX([NOTES.MODIFIEDDATE])
EDIT2:
SELECT USERID
FROM [PROJ]
INNER JOIN [NOTES] ON [PROJ].id = [NOTES].projID
WHERE [PROJ.STATUS] = 'ACTIVE'
AND [NOTES.MODIFIEDDATE] <= GETDATE() - 7
GROUP BY USERID, PROJECT
HAVING MAX([NOTES.MODIFIEDDATE])
Related Topics
Date Range for Set of Same Data
Finding The Decade with Largest Records, SQL Server
Can You Use Auto-Increment in MySQL with Out It Being The Primary Key
Sql: Insert Into...Values..Select
Microsoft SQL Server: Any Way to Tell When a Record Was Created
Order by a Field Being Equal to a Specific Value
Drop Foreign Keys Generally in Postgres
How to Get Current/Todays Date Data in SQL Server
How to Control Nullability in Select into for Literal-Based Columns
Error While Uploading a Report
Performance of Querying Across Two MySQL Databases on The Same Server
Error: Subquery Must Return Only One Column
The Multi-Part Identifier Could Not Be Bound - Subquery
How to Use Sum for Bit Columns