Making sense of the Audit table in CRM - dynamics-crm

I'm attempting to extract all the Merged records out of CRM and I see in the "Audit History" page of a Contact record the following:
If I click on it, I get the following:
And if I profile the code to see what SQL runs, it executes the following:
exec sp_executesql N'select
"audit0".AuditId as "auditid"
, "audit0".AttributeMask as "attributemask"
, "audit0".ChangeData as "changedata"
, "audit0".CreatedOn as "createdon"
, "audit0".Action as "action"
, "audit0".Operation as "operation"
, "audit0".CallingUserId as "callinguserid"
, "audit0".UserId as "userid"
, "audit0".ObjectId as "objectid"
, "audit0".ObjectTypeCode as "objecttypecode"
, "audit0".CallingUserIdName as "callinguseridname"
, "audit0".UserIdName as "useridname"
, "audit0".ObjectIdName as "objectidname"
from
Audit as "audit0"
where
("audit0".AuditId = #AuditId0)',N'#AuditId0 uniqueidentifier',
#AuditId0='7FE1B120-87EC-E811-8BE0-005056B12EA2'
with the results shown as:
Does anyone know how I get the Yes record that it was actually merged? I can't make sense of the results on how they get displayed as Old Value v New Value.

When you click the Save button on the record in CRM there's one audit row created in SQL, which describes all the changes made by this save. Only the old values are stored in SQL.
So how to get new values?
You can sort audit query by createdon ascending and for every row the new value is the next's row old value. To get the final new value you should join audit table with the contact table and get the Merged field value from the contact table.

Related

Update query is working on all rows even after selecting the particular values in oracle

I have written a query where I want to just update some of the LINK_ID. But it is updating all the rows in that table.
Here is my query
UPDATE APP_FIBERINV.TBL_FIBER_INV_CMPAPPROVED_INFO
SET NE_LENGTH =
(select MAINT_ZONE_NE_SPAN_LENGTH from APP_FIBERINV.TBL_FIBER_INV_JOBS WHERE LINK_ID IN ('MORV_1020','ANND_1017','BBSR_1047','DLHI_5417','MYSR_0104'));
I still doubt that the update statement you have posted updates all rows in the table. It must throw an error
ORA-01427: single-row subquery returns more than one row
instead, because your subquery returns five rows where it must be one, as you must find one value for each row you want to update.
This means your subquery is wrong. It selects five rows, where it must select one. You don't want to find the five values for 'MORV_1020', 'ANND_1017', but the one value for the link ID of the row you are updating.
You also want to update certain rows (those with the five link IDs), so you must add a WHERE clause at the end of your update statement.
UPDATE app_fiberinv.tbl_fiber_inv_cmpapproved_info i
SET ne_length =
(
SELECT j.maint_zone_ne_span_length
FROM app_fiberinv.tbl_fiber_inv_jobs j
WHERE j.link_id = i.span_link_id
)
WHERE span_link_id IN ('MORV_1020', 'ANND_1017', 'BBSR_1047', 'DLHI_5417', 'MYSR_0104');
Assuming both tables share the LINK_ID as primary and foreign key, you could just use a MERGE:
MERGE INTO APP_FIBERINV.TBL_FIBER_INV_CMPAPPROVED_INFO APPR_NFO
USING (
SELECT LINK_ID, MAINT_ZONE_NE_SPAN_LENGTH
FROM APP_FIBERINV.TBL_FIBER_INV_JOBS
WHERE LINK_ID IN ('MORV_1020','ANND_1017','BBSR_1047','DLHI_5417','MYSR_0104')
) INV_JOBS
ON ( APPR_NFO.SPAN_LINK_ID = INV_JOBS.LINK_ID)
WHEN MATCHED THEN UPDATE SET APPR_NFO.NE_LENGTH = INV_JOBS.MAINT_ZONE_NE_SPAN_LENGTH;

Multiple records update validation with the entire data set

Currently, I have an endpoint that allows the update of multiple records. Before saving the changes to the database I need to validate the data that is being sent from the front end.
I am having an issue with some kinds of validations that require checks against all the other records in the database table. (Ex: ate intervals overlaps/gaps, unique pairs checks).
In these cases when I try to do the validations I have two sets of data
The data sent from the front end that are stored in memory/variable.
The data on the database.
For the validations to be run correctly I need a way to merge the data in memory(the updated records) with the data in a database(original records + other data that is not currently being updated).
Is there a good way of doing this that does not require loading everything on the memory and merging both datasets there?
Another idea I am thinking of is to open a database transaction set the new data to the database and then when executing the gaps/overlap check queries use dirty read. I don't know if this is a good approach though.
Extra notes:
I am using Oracle as a database and Dapper to communicate with it.
The tables that need validation usually hold millions of records.
The same issue is for the create endpoint.
Another example
I am trying to create entities. The create endpoint is called and it has these data on the body (date format dd/mm/yyy):
StartDate
EndDate
01/01/2022
05/01/2022
10/01/2022
11/01/2022
12/01/2022
15/01/2022
In database I have these records saved:
Id
StartDate
EndDate
1
06/01/2022
09/01/2022
2
16/01/2022
20/01/2022
I need to check if there are any gaps between the dates. If there are I need to send a warning to the user(data in the database can be invalid - the application has old data and I can't do anything about that at the moment).
The way I check for this right now is like by using the SQL below
WITH CTE_INNERDATA AS(
SELECT s.STARTDATE, s.ENDDATE
FROM mytable s
WHERE FK = somefkvalue
UNION ALL
SELECT :StartDt AS STARTDATE, :EndDt AS ENDDATE FROM DUAL -- this row contains the data from one of the rows that came form the front-end
),
CTE_DATA AS (
SELECT ctid.STARTDATE, ctid.ENDDATE, LAG(ctid.ENDDATE, 1) OVER (ORDER BY ctid.STARTDATE) AS PREV_ENDDATE FROM CTE_INNERDATA ctid
)
SELECT COUNT(1) FROM cte_data ctd
WHERE PREV_ENDDATE IS NOT NULL
AND PREV_ENDDATE < STARTDATE
Using this SQL query when validating the third row (12/01/2022 - 15/01/2022) there will be a gap between dates 09/01/2022 and 12/01/2022.
This issue would be fixed if instead of using union with a single row, to use it with all the rows send from the front-end but I can't figure out a way to do something like that.
#Update
I iterate through the records the frontend sent and call this method to check for gaps.
private async Task ValidateIntervalGaps(int someFkValue, DateTime startdate, DateTime endDate)
{
var connection = _connectionProvider.GetOpenedConnection();
var gapsCount = await connection.QueryFirstAsync<int>(#"<<Query from above>>",
new { StartDt = startdate, EndDt = endDate, somefkvalue= someFkValue });
if (gapsCount > 0)
{
// Add warning message here
}
}

h2 index corruption? embedded database loaded with runscript has "invisible" rows

Using h2 in embedded mode, I am restoring an in memory database from a script backup that was previously generated by h2 using the SCRIPT command.
I use this URL:
jdbc:h2:mem:main
I am doing it like this:
FileReader script = new FileReader("db.sql");
RunScript.execute(conn,script);
which, according to the doc, should be similar to this SQL:
RUNSCRIPT FROM 'db.sql'
And, inside my app they do perform the same. But if I run the load using the web console using h2.bat, I get a different result.
Following the load of this data in my app, there are rows that I know are loaded but are not accessible to me via a query. And these queries demonstrate it:
select count(*) from MY_TABLE yields 96576
select count(*) from MY_TABLE where ID <> 3238396 yields 96575
select count(*) from MY_TABLE where ID = 3238396 yields 0
Loading the web console and using the same RUNSCRIPT command and file to load yields a database where I can find the row with that ID.
My first inclination was that I was dealing with some sort of locking issue. I have tried the following (with no change in results):
manually issuing a conn.commit() after the RunScript.execute()
appending ;LOCK_MODE=3 and the ;LOCK_MODE=0 to my URL
Any pointers in the right direction on how I can identify what is going on? I ended up inserting :
Server.createWebServer("-trace","-webPort","9083").start()
So that I could run these queries through the web console to sanity check what was coming back through JDBC. The problem happens consistently in my app and consistently doesn't happen via the web console. So there must be something at work.
The table schema is not exotic. This is the schema column from
select * from INFORMATION_SCHEMA.TABLES where TABLE_NAME='MY_TABLE'
CREATE MEMORY TABLE PUBLIC.MY_TABLE(
ID INTEGER SELECTIVITY 100,
P_ID INTEGER SELECTIVITY 4,
TYPE VARCHAR(10) SELECTIVITY 1,
P_ORDER DECIMAL(8, 0) SELECTIVITY 11,
E_GROUP INTEGER SELECTIVITY 1,
P_USAGE VARCHAR(16) SELECTIVITY 1
)
Any push in the right direction would be really appreciated.
EDIT
So it seems that the database is corrupted in some way just after running the RunScript command to load it. As I was trying to debug to find out what is going on, I tried executing the following:
delete from MY_TABLE where ID <> 3238396
And I ended up with:
Row not found when trying to delete from index "PUBLIC.MY_TABLE_IX1: 95326", SQL statement:
delete from MY_TABLE where ID <> 3238396 [90112-178] 90112/90112 (Help)
I then tried dropping and recreating all my indexes from within the context, but it had no effect on the overall problem.
Help!
EDIT 2
More information: The problem occurs due to the creation of an index. (I believe I have found a bug in h2 and I have working on creating a minimal case that reproduces it). The simple code below will reproduce the problem, if you have the right set of data.
public static void main(String[] args)
{
try
{
final String DB_H2URL = "jdbc:h2:mem:main;LOCK_MODE=3";
Class.forName("org.h2.Driver");
Connection c = DriverManager.getConnection(DB_H2URL, "sa", "");
FileReader script = new FileReader("db.sql");
RunScript.execute(c,script);
script.close();
Statement st = c.createStatement();
ResultSet rs = st.executeQuery("select count(*) from MY_TABLE where P_ID = 3238396");
rs.next();
if(rs.getLong(1) == 0)
System.err.println("It happened");
else
System.err.println("It didn't happen");
} catch (Throwable e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
I have reduced the db.sql script to about 5000 rows and it still happens. When I attempted to go to 2500 rows, it stopped happening. If I remove the last line of the db.sql (which is the index creation), the problem will also stop happening. The last line is this:
CREATE INDEX PUBLIC.MY_TABLE_IX1 ON PUBLIC.MY_TABLE(P_ID);
But the data is an important player in this. It still appears to only ever be the one row and the index somehow makes it inaccessible.
EDIT 3
I have identified the minimal data example to reproduce. I stripped the table schema down to a single column, and I found that the values in that column don't seem to matter -- just the number of rows. Here is the contents of (snipped with obvious stuff) of my db.sql generated via the SCRIPT command:
;
CREATE USER IF NOT EXISTS SA SALT '8eed806dbbd1ea59' HASH '6d55cf715c56f4ca392aca7389da216a97ae8c9785de5d071b49de5436b0c003' ADMIN;
CREATE MEMORY TABLE PUBLIC.MY_TABLE(
P_ID INTEGER SELECTIVITY 100
);
-- 5132 +/- SELECT COUNT(*) FROM PUBLIC.MY_TABLE;
INSERT INTO PUBLIC.MY_TABLE(P_ID) VALUES
(1),
(2),
(3),
... snipped you obviously have breaks in the bulk insert here ...
(5143),
(3238396);
CREATE INDEX PUBLIC.MY_TABLE_IX1 ON PUBLIC.MY_TABLE(P_ID);
But that will recreate the problem. [Note that my numbering skips a number every time there was a bulk insert line. So there really is 5132 rows, though you see 5143 select count(*) from MY_TABLE yields 5132]. Also, I seem to be able to recreate the problem in the WebConsole directly now by doing:
drop table MY_TABLE
runscript from 'db.sql'
select count(*) from MY_TABLE where P_ID = 3238396
You have recreated the problem if you get 0 back from the select when you know you have a row in there.
Oddly enough, I seem to be able to do
select * from MY_TABLE order by P_ID desc
and I can see the row at this point. But going directly for the row:
select * from MY_TABLE where P_ID = 3238396
Yields nothing.
I just realized that I should note that I am using h2-1.4.178.jar
The h2 folks have already apparently resolved this.
https://code.google.com/p/h2database/issues/detail?id=566
Just either need to get the code from version control or wait for the next release build. Thanks Thomas.

Performing the jdbc transaction in right way

I have a database table that logs the changes occur in other tables. table structure for my log table is as following.
Log_Table(id, table_name, operation, flag)
values (1, Customer_Table, 1, 1);
values (2, Customer_Table, 2, 1);
values (3, Customer_Table, 1, 1);
values (4, Customer_Table, 2, 1);
values (5, Customer_Table, 1, 1);
I update this table against a button on a web page by doing following operations:
/* first */
public List<Long> select_Changes()
{
select id from Log_Table where flag =1;
}
/* (wait for user input) */
/* second */
public void update_table(List<Long> ids)
{
update Log_Table set flag =0 where id in( ids)
}
Problem is that between first and second operation its up to the user to perform the operation. Meanwhile another user at same time does the same operations. I don't want rows already selected by the first user to be selected by the second user; that is, when the second user runs the first step (assuming two more rows have been added since the first user ran it), the result should be:
values(6,Customer,2,1);
values(7,Customer,1,1);
Please suggest what I should do? I need to lock the rows for any kind of operation after rows are get selected. I tried select for update clause but it did not solve the problem. It's in a web application.
It is almost never a good idea to hold a database transaction open while waiting for user input. What if the user goes to lunch while the transaction is pending, or their network connection goes down and isn't restored for days?
Also, you don't say what database product you are using. Depending on the product, its configuration, and the transaction isolation level, the results of the concurrent attempt what the transaction is pending, so if you want portable behavior you can't rely on the behavior of SELECT FOR UPDATE or even more standardized features.
My recommendation would be to provide a way in the row to identify pending rows, which are waiting for user confirmation. You could use three states for the flag column, to represent something like available, pending, and taken; however, you probably want to have some way to recognize rows which were presented to a user but for which the user never clicked "OK" or "Cancel" (or whatever the options are). If you add a timestamp column for that purpose, you could stay with two states for the flag column and use something like this (assuming that you are using databases which support the RETURNING clause) for the first step:
public List<Long> select_Changes()
{
UPDATE Log_Table
SET when_presented = CURRENT_TIMESTAMP
WHERE flag = 1
AND when_presented = NULL
RETURNING id, when_presented;
}
The second step would be changed to:
public void update_table(List<Long> ids)
{
UPDATE Log_Table
SET flag = 0
WHERE id IN (ids)
AND when_presented = time_claimed;
}
The second step would not necessarily need to change, but with the change above, you could use another RETURNING clause to confirm which id values this user actually claimed, closing a race condition otherwise present if a maintenance process set when_presented back to NULL on an apparently abandoned set of rows which were then presented to another user right before the first user belatedly tried to claim them.
I have added a timestamps column and an extra table with the structure
Last_Oeration_Time(id number, last_op_time timestamp(6))
When the first user clicks the button i run an sql insert query on Last_Oeration_Time like
insert int Last_Oeration_Time(id,last_op_time) values(seq_lasst_op_time_id.nextval,sysdate)
now when the second user runs the first step (assuming two more rows have been added since the first user ran it), the result is desired result. is this ok?

How to get the latest date inserted from the table with Linq to entities

how to retrieve the latestdate inspected from a column
In our app a user can inspect an item and when it inspected the current date is entered into the table. For the same item someother can uninspect it this time nothing is inserted into the table.
Another user can inspect it and current date is inserted
I need to get the LatestDate Inserted..how to get this with Linq
Let say table name is Statuses and col name is LastdateInspected
Sounds like you want something like:
var query = db.Statuses
.OrderByDescending(x => x.LastDateInspected)
.FirstOrDefault();
That will return null if there are no entries, or the value with the latest LastDateInspected value otherwise (i.e. the first result, having ordered by the last date inspected latest-first).
That will get you the whole record, of course. If you only want the date, you can select the LastDateInspected column.

Resources