T-SQL - joining a transaction table to an audit table - sql-server

Say I have these two tables:
Transaction Table
Pmt ID VendorID PaymentDate
1 1 2017-10-01 00:14:42
2 2 2017-09-03 00:08:23
The second table has a list of those VendorIDs, and everytime the associated email changed. It could have changed tons of times.
Audit Table
VendorID Email CreateDateUTC
1 a#gmail.com 2016-01-01 17:51:08
1 b#gmail.com 2016-03-03 12:40:03
1 c#gmail.com 2017-01-10 03:40:04
2 li#gmail.com 2017-03-30 05:40:03
Edit: So say this would show that any payment that went to vendor id 1 after 2016-01-01 17:51:08 but before 2016-03-03 12:40:03 went to a#gmail.com. Any payment that went to vendor id 1 after 2016-03-03 12:40:03 but before 2017-01-10 03:40:04 went to b#gmail.com. And that anything to vendor id 1 that went after 2017-01-10 03:40:04 went to c#gmail.com (unless of course, there's another more recent entry for vendor 1 in the Audit Table).
If I say - wanted to know every transaction that went out to email example#gmail.com, how could I query that?
My assumption is I'd take the transaction table - then join the audit table. Then OK, we have every transaction, and the email it went to. But, how to join only the correct email? Or, am I maybe thinking about this the wrong way entirely?

You Have to create one vendor master in which only main distinct vendor is stored with unique id.
Then create a sub table vendor contact detail.In that add the more than on contact detail for the vendor created in the master and in vendor contact detail also insert one field isPrimary that is bifurcate the Vendor address to be chosen.
then make join and do the task

Need more info, but maybe this will work?
select distinct t.PmtID, t.VendorID, t.PaymentDate
from tblTrans t
inner join tblAudit a
on t.VendorID = a.VendorID
where t.PaymentDate <= a.CreateDateUTC
and a.Email = 'a#gmail.com'
order by t.PaymentDate

The following query returns all rows from transaction table and it matches audit table and gets the email ID to which the email has been sent at the time of transaction
SELECT * FROM
(
SELECT VENDOR.*,Audit.Email,ROW_NUMBER() OVER(PARTITION BY
Vendor.VendorID ORDER BY DATEDIFF(D,CreateDateUTC, PaymentDate) DESC) RNo
FROM Vendor LEFT OUTER JOIN Audit ON Vendor.VendorId =Audit.VendorId
WHERE PaymentDate > CreateDateUTC
)T
WHERE RNo = 1

Related

Use a single query to find all Details records if one is updated?

I am using SQL Server 2017. There are two tables: Master table and Details table. If a record in the Details table is updated today, then all records in the Details table associated with the same master record in the Master table as the updated details record should be found, together with some info from the Master table. This is an example:
Master table
id name
----------------
1 master1
2 master2
Details table
id master_id info update_date
-----------------------------------
1 1 details1 2021-09-07
2 1 details2 2021-09-01
3 2 details2 2021-09-03
Suppose that today is 2021-09-07. Then the needed query should return
1 1 master1 details1 2021-09-07
1 2 master1 details2 2021-09-01
The first two columns are the ids for Master and Details records.
I am able to use a query to find the Details records that are updated today through a simple join with a condition on the update_date field. I am unable to use a SINGLE query to find other Details records (if any), at the same time, associated with the same Master record as an updated Details record is.
It is possible that two ore more Details records associated with the same Master record are updated today, then the results should not contain duplicate entries. For example, if #2 Details record is updated today as shown below:
id master_id info update_date
-----------------------------------
1 1 details1 2021-09-07
2 1 details2 2021-09-07
3 2 details2 2021-09-03
Then the results should be:
1 1 master1 details1 2021-09-07
1 2 master1 details2 2021-09-07
How to use a single query to return the needed results?
Let's start with a subquery to find the master_id values you need.
SELECT DISTINCT master_id
FROM details
WHERE update_date = <<the desired date>>
Then we can use that in a query to obtain your result set.
SELECT details.id, details.master_id,
master.name, details.info, details.update_date
FROM master
JOIN details ON master.id = details.master_id
WHERE master.id IN (
SELECT DISTINCT master_id
FROM details
WHERE update_date = <<the desired date>>
)
SQL is all about sets of records. So the subquery gets the set of master_id values you need for the date you need, then uses that set to get the detail records you need.
maybe the query you are looking for is
select
D.master_id, D.id, M.name, D.info, D.update_date
from Details D
inner join Master M
on M.id =D.master_id
and D.master_id in
(
select
distinct master_id
from Details
where
update_date = CAST(GETDATE() as DATE)
)
SELECT MT.* FROM masterTable MT WHERE EXISTS (SELECT TOP(1) 1 FROM detailsTable DT WHERE MT.id = DT.master_id AND update_date = CONVERT(DATE,GETDATE()));

Replacing data in one table with data in another table using a unique ID

I'm using Access 2016 to view data from a table on our SQL server. I have a massive audit log where the record being viewed is represented by a "FolderID" field. I have another table that has values for the FolderID (represented as "fid") along with columns identifying the record's name and other ID numbers.
I want to be able to replace the FolderID value in the first table with CUSTOMER_NAME value from the second table so I know what's being viewed at a glance.
I've tried googling different join techniques to build a query that will accomplish this, but my google-fu is weak or I'm just not caffeinated enough today.
Table 1.
EventTime EventType FolderID
4/4/2019 1:23:39 PM A 12345
Table 2
fid acc Other_ID Third_ID CUSTOMER_NAME
12345 0 9875 12345678 Doe, John
Basically I want to query Table 2 to search for fid using the value in Table 1 for FolderID, and I want it to respond with the CUSTOMER_NAME associated with the FolderID/fid. The result would look like:
EventTime EventType FolderID
4/4/2019 1:23:39 PM A Doe, John
I'm stupid because I thought I was too smart to use the freaking Query Wizard. When I did, and it prompted me to create relationships and actually think about what I was doing, it came up with this.
SELECT [table1].EventTime, [table1].EventType, [table1].FolderID, [table1].ObjRef, [table1].AreaID, [table1].FileID, [table2].CUSTOMER_NAME, [table2].fid FROM [table2]
LEFT JOIN [table1] ON [table2].[fid] = [table1].[FolderID];
You can run this query and check if it helps!.
Select EventTime, EventType , CUSTOMER_NAME AS FolderID FROM Table1, Table2 Where Table1.FolderID = Table2.fid;
Basically, 'AS' is doing what you want here as you can rename your column to whatever you want.

How to accummulate two datetime in two tables as VIEW in SQL Server 2014?

How to query to accumulate two datetime columns in two tables in SQL Server 2014? This is an example for your reference:
Check-In table
InID UserID CheckInTime
---------------------------------
IN-001 1 2018-11-10 08:00:00
IN-002 2 2018-11-15 07:00:00
Check-Out table
OutID UserID CheckOutTime
----------------------------------
OUT-001 1 2018-11-10 12:00:00
OUT-002 2 2018-11-15 14:00:00
Result set (expected)
ResultID UserID InID OutID WorkTimeinHour
--------------------------------------------------------
1 1 IN-001 OUT-001 4
2 2 IN-002 OUT-002 7
Similar to #PSK, I used STUFF function to replace "IN-" and "OUT-" characters
But since these are in JOIN conditions, those operations will cause performance loss
It is better to use a numeric column in both tables instead of useless "IN-" and "OUT-" containing string columns
select
i.UserId, i.InID, CheckInTime, o.OutID, CheckOutTime,
dbo.fn_CreateTimeFromSeconds(DATEDIFF(ss, CheckInTime, CheckOutTime)) as TotalTime
from CheckIn i
inner join CheckOut o
on i.UserId = o.UserId and
STUFF (i.InID,1,3,'') = STUFF (o.OutID,1,4,'')
Additionally, I used a custom user-defined fn_CreateTimeFromSeconds function to format time for HH:MI:SS format
Hope it helps
For your current scenario, you can try like following.
Assuming that IN and OUT id after the "-" will be same as one entry.
SELECT ROW_NUMBER()
OVER(
ORDER BY (SELECT NULL)) AS ResultIt,
T1.inid,
T2.outid,
DATEDIFF(hh, T2.checkouttime, T1.checkintime)
FROM checkin T1
INNER JOIN checkout T2
ON REPLACE(T1.inid, 'IN-', '') = REPLACE(T2.outid, 'OUT-', '')
This query will not perform good for huge data as REPLACE is being used in the JOIN. Ideally you should have a single identifier to identify the IN and OUT transaction.

Delete latest entry in SQL Server without using datetime or ID

I have a basic SQL Server delete script that goes:
Delete from tableX
where colA = ? and colB = ?;
In tableX, I do not have any columns indicating sequential IDs or timestamp; just varchar. I want to delete the latest entry that was inserted, and I do not have access to the row number from the insert script. TOP is not an option because it's random. Also, this particular table does not have a primary key, and it's not a matter of poor design. Is there any way I can do this? I recall mysql being able to call something like max(row_number) and also something along the lines of limit one.
ROW_NUMBER exists in SQL Server, too, but it must be used with an OVER (order_by_clause). So... in your case it's impossible for you unless you come up with another sorting algo.
MSDN
Edit: (Examples for George from MSDN ... I'm afraid his company has a Firewall rule that blocks MSDN)
SQL-Code
USE AdventureWorks2012;
GO
SELECT ROW_NUMBER() OVER(ORDER BY SalesYTD DESC) AS Row,
FirstName, LastName, ROUND(SalesYTD,2,1) AS "Sales YTD"
FROM Sales.vSalesPerson
WHERE TerritoryName IS NOT NULL AND SalesYTD <> 0;
Output
Row FirstName LastName SalesYTD
--- ----------- ---------------------- -----------------
1 Linda Mitchell 4251368.54
2 Jae Pak 4116871.22
3 Michael Blythe 3763178.17
4 Jillian Carson 3189418.36
5 Ranjit Varkey Chudukatil 3121616.32
6 José Saraiva 2604540.71
7 Shu Ito 2458535.61
8 Tsvi Reiter 2315185.61
9 Rachel Valdez 1827066.71
10 Tete Mensa-Annan 1576562.19
11 David Campbell 1573012.93
12 Garrett Vargas 1453719.46
13 Lynn Tsoflias 1421810.92
14 Pamela Ansman-Wolfe 1352577.13
Returning a subset of rows
USE AdventureWorks2012;
GO
WITH OrderedOrders AS
(
SELECT SalesOrderID, OrderDate,
ROW_NUMBER() OVER (ORDER BY OrderDate) AS RowNumber
FROM Sales.SalesOrderHeader
)
SELECT SalesOrderID, OrderDate, RowNumber
FROM OrderedOrders
WHERE RowNumber BETWEEN 50 AND 60;
Using ROW_NUMBER() with PARTITION
USE AdventureWorks2012;
GO
SELECT FirstName, LastName, TerritoryName, ROUND(SalesYTD,2,1),
ROW_NUMBER() OVER(PARTITION BY TerritoryName ORDER BY SalesYTD DESC) AS Row
FROM Sales.vSalesPerson
WHERE TerritoryName IS NOT NULL AND SalesYTD <> 0
ORDER BY TerritoryName;
Output
FirstName LastName TerritoryName SalesYTD Row
--------- -------------------- ------------------ ------------ ---
Lynn Tsoflias Australia 1421810.92 1
José Saraiva Canada 2604540.71 1
Garrett Vargas Canada 1453719.46 2
Jillian Carson Central 3189418.36 1
Ranjit Varkey Chudukatil France 3121616.32 1
Rachel Valdez Germany 1827066.71 1
Michael Blythe Northeast 3763178.17 1
Tete Mensa-Annan Northwest 1576562.19 1
David Campbell Northwest 1573012.93 2
Pamela Ansman-Wolfe Northwest 1352577.13 3
Tsvi Reiter Southeast 2315185.61 1
Linda Mitchell Southwest 4251368.54 1
Shu Ito Southwest 2458535.61 2
Jae Pak United Kingdom 4116871.22 1
Your current table design does not allow you to determine the latest entry. YOu have no field to sort on to indicate which record was added last.
You need to redesign or pull that information from the audit tables. If you have a database without audit tables, you might have to find a tool to read the transaction logs and it will be a very time-consuming and expensive process. Or if you know the date the records you want to remove were added, you could possibly use a backup from just before this happened to find the records that were added. Just be awwre that you might be looking at records changed after this date that you want to keep.
If you need to do this on a regular basis instead of one-time to fix some bad data, then you need to properly design your database to include an identity field and possibly a dateupdated field (maintained through a trigger) or audit tables. (In my opinion no database containing information your company is depending on should be without audit tables, one of the many reasons why you should never allow an ORM to desgn a database, but I digress.) If you need to know the order records were added to a table, it is your responsiblity as the developer to create that structure. Databases only store what is deisnged for tehm to store, if you didn't design it in, then it is not available easily or at all
If (colA +'_'+ colB) can not be dublicate try this.
declare #delColumn nvarchar(250)
set #delColumn = (select top 1 DeleteColumn from (
select (colA +'_'+ colB) as DeleteColumn ,
ROW_NUMBER() OVER(ORDER BY colA DESC) as Id from tableX
)b
order by Id desc
)
delete from tableX where (colA +'_'+ colB) =#delColumn

update table with values from 2 other tables

I would like to find the nearest Employee for my Customer and update in order table. I tried a Query which throws an error. Can any one suggest what am doing wrong on my query? The only select Statement is working fine. But the update looks some thing wrong.
I have 3 tables
Customer_Master
Customer_ID Customer_Name WHID Cust_Location
Cust100001 Subash WH10001 0xE6100000010C1B2E724F57172A408449F1F109685340
Cust100002 Naresh WH10002 0xE6100000010CBE30992A18152A4093AAED26F8675340
Employee_Master
Emp_ID Emp_name WHID Emp_Location
Emp100001 Prakash WH10001 0xE6100000010C363B527DE7172A4069C36169E0675340
Emp100002 Suresh WH10002 0xE6100000010C98C3EE3B86172A4064E597C118685340
Emp100003 Vincent WH10001 0xE6100000010CE5B8533A58172A4090DD054A0A685340
Emp100004 Paul WH10002 0xE6100000010C2EE6E786A6142A40A0A696ADF5675340
Order_Tran
Order_ID Cust_ID Emp_ID
ORD19847 Cust100001 ?????
ORD19856 Cust100002 ?????
I have Location of the customer and also Employee in Master Tables. Now i want to update Emp_ID in Order_Tran table who is nearest to the customer location in Order Table for Customer Cust100001.
I tried the below query which is showing error
Update Order_Tran Set Emp_ID=(Select Top (1) Emp_ID, Employee_Master.Emp_Location.STDistance(Customer_Master.Cust_Location) AS DistanceApart FROM Customer_Master, Employee_Master WHERE Customer_ID = 'Cust100001'
and Customer_Master.WHID = Employee_Master.WHID ORDER BY DistanceApart);
Try selecting a single value in your sub-query (to stop the error) and adding an outer where clause (to ensure only the specified employee is updated).
UPDATE Order_Tran
SET Emp_ID=(SELECT TOP (1) Emp_ID
FROM Customer_Master, Employee_Master
WHERE Customer_ID = 'Cust100001'
AND Customer_Master.WHID = Employee_Master.WHID
ORDER BY Employee_Master.Emp_Location.STDistance(Customer_Master.Cust_Location))
WHERE Customer_ID = 'Cust100001'

Resources