SSIS audit step encountering errors - sql-server

I have a step in my SSIS package where I'd like to update the latest row in my execution log (T1) with information from the latest row in another table (T2).
I get an error around the 'Where' statement
UPDATE T1
SET
[Survey_Size] = ssd.[FileName]
,Survey_Start_Date = ssd.[Start_Date]
,Survey_End_Date = ssd.[End_Date]
,[EndTime] = getdate()
,loaded = 1
FROM (SELECT max(log_sk) AS maxSk FROM T1) A
JOIN (SELECT max(PK) AS maxPK FROM T2) SS
JOIN (SELECT PK, [FileName], Start_Date, End_Date, Survey_Size FROM T2) ssd ON ss.maxPK = ssd.pk
WHERE log_sk = a.maxSk
Table 1 looks like this:
log_sk | FileName | Survey_Size | Start_Date | End_Date
and I'd like to update the information from Table 2 which looks like below, where FileName would be a joining key in both
PK | FileName | Start_Date | End_Date | Survey_Size

I rewrite it with CTE Because it's more efficient and much more readable.
;With LastT1 as (
Select
log_sk as ID,
Survey_Size,
Survey_Start_Date,
Survey_End_Date,
EndTime,
loaded,
ROW_NUMBER() over (order by log_sk Desc) as Row_No
From T1
), LatestT2 as (
Select
PK as ID,
[FileName],
[Start_Date],
End_Date,
Survey_Size,
ROW_NUMBER() over (order by PK Desc) as Row_No
From T2
)
Update Source
Set
Source.[Survey_Size] = LatestT2.[FileName],
Source.Survey_Start_Date = LatestT2.[Start_Date],
Source.Survey_End_Date = LatestT2.[End_Date],
Source.[EndTime] = getdate(),
Source.loaded = 1
From LastT1 as Source
Inner Join LatestT2 on Source.ID = LatestT2.ID and LatestT2.Row_No = 1
Where Source.Row_No = 1

Related

How to join columns from the same table?

How to add extra column with time difference for the same SALESID and GO = SO and GO = ZW?
select SALESID, DATETIME AS Time, GO
FROM [Mer_PRD].[dbo].[TRACKINGTABLE]
WHERE GO IN('ZW', 'SO')
Result example:
****SALESID** | TIME SO | TIME ZW | DIFF**
ZS/0033428/2020 | 2020-07-16 08:37:00 | 2020-07-16 08:40:00 | 00:03:00
You could use a self join.
SELECT goSO.SALESID
, goSo.[Time] 'TIME SO'
, goZw.[Time] 'TIME ZW'
, cast(goZw.[Time] - goSo.[Time] as Time) Difference
FROM GOTRACKING goSo
INNER JOIN GOTRACKING goZw on goSo.SALESID = goZw.SALESID
WHERE goSo.[GO] = 'SO'
AND goZw.[GO] = 'ZW'
SQLFiddle
try this,
SELECT SALESID, Time FROM [Mer_PRD].[dbo].[TRACKINGTABLE]
;WITH cte AS (SELECT SALESID, Time, ROW_NUMBER()OVER(PARTITION BY SALESID ORDER BY Time) AS RN
FROM [Mer_PRD].[dbo].[TRACKINGTABLE])
SELECT a.SALESID, a.Time, b.Time AS Time2
FROM cte a
LEFT JOIN cte b
ON a.SALESID = b.SALESID
AND a.RN = b.RN -1
WHERE a.RN = 1

Group By and inner join with latest records based on TimeStamp

I have a History table as below:
ID | GroupCode | Category | TimeStamp
---+-----------+----------+-----------
1 | x | shoes | 2016-09-01
2 | y | blach | 2016-09-01
History table gets updated every month and a single entry for each GroupCode gets inserted in the table.
I have also a Current table which holds the latest position.
Before or after I update the History table with the current position I would like to find out whether the Category has changed from last month to this month.
I need to compare the last Category with the current Category and, if it has changed, then flag the CategoryChanged in the Current table.
Current table:
ID | GroupCode | Category | CategoryChanged
---+-----------+----------+----------------
1 | x | shoes | True
2 | y | blah | False
I tried to achieve this with INNER JOIN but I am having difficulties to INNER JOIN to latest month and year entries in History table, but no success.
--get highest group code based on timestamp
;with History
as
(select top 1 with ties groupcode,category
from
history
order by
row_number() over (partition by group code order by timestamp desc) as rownum
)
--now do a left join with current table
select
ct.ID,
ct.GroupCode,
ct.Category,
case when ct.category=ht.category or ht.category is null then 'False'
else 'true'
end as 'changed'
from
currenttable ct
left join
history ht
on ht.groupcode=ct.groupcode
use below to update ,after checking if your select values are correct..
update ct
set ct.category=
case when ct.category=ht.category or ht.category is null then 'False'
else 'true'
end
from
currenttable ct
left join
history ht
on ht.groupcode=ct.groupcode
if you make a CTE where the history records have rown_numbwer for each GroupCode ordered by date descending, then you are interested in rows 1 AND 2, SO YOU CAN THEREFORE join your CTE on GroupCode, and select records 1 and 2, you can the see if category has changed between rows 1 and 2
;WITH CTE AS (SELECT *, row_number() OVER (PARTITION BY GroupCode ORDER BY TimeStamp Desc) RN FROM History)
SELECT
C1.ID,
C1.GroupCode,
C1.Category,
CASE WHEN C1.Category = C2.Category THEN
'false'
else
'true'
end AS CategoryChanged
FROM CTE C1
JOIN
CTE C2
ON C1.GroupCode = C2.GroupCode
AND C1.Rn=1 AND C2.RN = 2;
if you have null categories, you can avoid with - BTW you will need to learn how to handle NULLs the way you want to handle them - you can't expect people to post on here thinking about NULLs you never mentioned forever! And happening to realise what you want to do with them for that matter
;WITH CTE AS (SELECT *, row_number() OVER (PARTITION BY GroupCode ORDER BY TimeStamp Desc) RN FROM History)
SELECT
C1.ID,
C1.GroupCode,
C1.Category,
CASE WHEN C1.Category = C2.Category OR C1.Category IS NULL AND C2.Category IS NULL THEN
'false'
else
'true'
end AS CategoryChanged
FROM CTE C1
JOIN
CTE C2
ON C1.GroupCode = C2.GroupCode
AND C1.Rn=1 AND C2.RN = 2;

How to get the latest entry for each item for in a Month with a single SQL query [duplicate]

This question already has answers here:
Fetch the rows which have the Max value for a column for each distinct value of another column
(35 answers)
Closed 6 years ago.
I am trying to write a query to pick one entry for each item for each month but the latest in the month from the following table:
Name | Date | Value
a |2015-01-01 | 1
a |2015-01-02 | 2
b |2015-01-03 | 1
b |2015-01-04 | 1
b |2015-01-03 | 3
c |2015-01-02 | 2
c |2015-01-29 | 10
a |2015-02-10 | 2
a |2015-02-20 | 1
c |2015-02-10 | 2
c |2015-02-22 | 23
b |2015-02-25 | 1
b |2015-02-19 | 2
return should be:
a |2015-01-02 | 2
b |2015-01-04 | 1
c |2015-01-29 | 10
a |2015-02-20 | 1
b |2015-02-25 | 1
c |2015-02-22 | 23
I wonder how would this be achieved instead of sending multiple queries to SQL server for each month I would like to load all the values with one query then filter the collection on the memory. Otherwise I would end up writing a query as below:
SELECT Name,Date, Value FROM MyTable mt
INNER JOIN (
select max(Date) as MaxDate
FROM [MyTable] m WHERE YEAR(Date) =YEAR(#date)
AND MONTH(Date)=MONTH(#date)) mx ON t.Date = mx.MaxDate)
And this query needs to be run for each month.
Any better idea to return all entries with a single query?
Thanks,
Try grouping by year and month in the derived table:
SELECT t1.Name, t1.[Date], t1.Value
FROM MyTable t1
INNER JOIN (
SELECT Name, YEAR(Date) AS y, MONTH([Date]) AS m, MAX([Date]) as MaxDate
FROM MyTable
GROUP BY Name, YEAR(Date), MONTH([Date])
) t2 ON t1.Name = t2.Name AND
YEAR(t1.[Date]) = t2.y AND MONTH(t1.[Date]) = t2.m AND
t1.[Date] = t2.MaxDate
SELECT *
FROM (
SELECT NAME, DATE, VALUE,
ROW_NUMBER() OVER (PARTITION BY NAME, YEAR(Date), MONTH(Date)
ORDER BY Date DESC) rn
FROM MyTable) AS t
WHERE t.rn = 1
Assuming that you are using a SQL Server version that supports it, you can use the ROW_NUMBER() windowing function to return a sequence number for each row, then you can subsequently use that to restrict to only the rows that you require.
SELECT [Name],[Date],[Value]
,ROW_NUMBER() OVER (PARTITION BY [Name] ORDER BY [Date] DESC) AS [Seq]
FROM myTable
Things to consider:
What happens when there is a tie? ROW_NUMBER will always return a sequence number, but if your data has > 1 row at the same Date value, the order will be arbritrary. To solve this add additional tie-break ORDER BY entries
How do I filter this? Put it into a Common Table Expression, Inline View or Real View
I think you need a correlated query once you have a set of distinct (Name, Month). There are various ways of doing this, one is to use cross apply:
select *
from (select distinct Name, Month(Date) as Month
from theTable) itemMonths
cross apply (select Max(value)
from theTable t
where Month(t.Date) = itemMonths.Month
and t.Name = itemMonths.Name)
You could try the following:
WITH MyTable AS
(SELECT 'a' AS name, GETDATE() AS date, 1 AS value
UNION ALL
SELECT 'a', GETDATE()+1, 2
)
, res AS (
SELECT Name,date,MAX(Date) OVER(PARTITION BY Name, DATEPART(yyyy,date), DATEPART(mm, date)) AS max_date , Value FROM MyTable
)
SELECT name,date,res.value FROM res WHERE date=max_date
You still need a filter though as the Max Over will return all rows.
If you were using Teradata I'd suggest using the Qualify Clause but Itzik hasn't had any luck getting this ported to SQL server!
https://connect.microsoft.com/SQLServer/feedback/details/532474
Use Cross apply
SELECT b.*
FROM mytable mt
CROSS apply (SELECT TOP 1 NAME, date, value
FROM [mytable] m
WHERE m.NAME = mt.NAME
AND Month(m.date) = Month(mt.date)
AND Year(m.date) = Year(mt.date)
ORDER BY m.date DESC) b

TSQL for updating TABLEA from tableB where no id's exist

I have the following table structure.
Table A
InvoiceNumber
InvoiceDate
Sku
SerialNumber
Table B
InvoiceNumber
Invoicedate
Sku
SerialNumber
Table B has valid SerialNumbers, while Table A does NOT (its blank). I would like to update Table A with table B's serial numbers.
There can be multiple records with the same invoiceNumber, Invoicedate and Sku, only serialNumber is unique.
If I do an
update tablea set serialNumber = tableb.serialNumber
where tablea.sku = tableb.sku
and tablea.invoicenumber = tableb.invoicenumber
and tablea.invoicedate = tableb.invoicedate
I end up getting duplicate serials in table a.
Sample Data
Table a
InvoiceNbr : 1 invoiceDate = 10/01/2015 sku = ABC serial = blank
InvoiceNbr : 1 invoiceDate = 10/01/2015 sku = ABC serial = blank
Table b
InvoiceNbr : 1 invoiceDate = 10/01/2015 sku = ABC serial = abc
InvoiceNbr : 1 invoiceDate = 10/01/2015 sku = ABC serial = xyz
No matter what I do I always end up with dupes in table a :|
Try this:
update tableA
set serialNumber = b.serialNumber
from (select *, row_number() over (partition by invoicenumber, invoicedate, sku order by serialnumber) rn from tableA) a
inner join
(select *, row_number() over (partition by invoicenumber, invoicedate, sku order by serialnumber) rn from tableB) b
on a.sku = b.sku and a.invoicenumber = b.invoicenumber and a.invoicedate = b.invoicedate and a.rn = b.rn
Demo
If I understand correctly, there are records in table B with all columns except serialNumber having same values, and your current update logic just fills table A with one of the values of serialNumber rather than a 1 to 1 update. The above solution uses row_number to create an extra identifier for each row in table B, and then uses that as an additional criteria to match the rows for updating.

calculate difference between two times in two rows in sql

I am using MSSQL 2008 Standard
I have multiple rows in a select command which are filled with events. For every event I have got a timestamp, now I want to calculate the time between the events:
(number) | event | timestamp | duration
---------+----------------+---------------------+----------
1 | logon | 2012-05-23 10:00:00 |
2 | incomming call | 2012-05-23 10:01:00 |
3 | call ended | 2012-05-23 10:02:00 |
4 | logoff | 2012-05-23 10:04:00 |
(the number column does not exist but it's easier for explanation)
Now the duration cell for the first row should be 1, for the second one also 1 and for the third one 2.
Does anybody know how to achieve this without loops and so on.
Thank you
You need a self join. Since you need to generate an id then something like:
select t1.*, datediff(minute, t2.timestamp, t1.timestamp) from
(select *, row_number() over (order by ...) as rowid from MyTable) t1
inner join
(select *, row_number() over (order by ...) as rowid from MyTable) t2
on t1.rowid = t2.rowid - 1
I found the CTE answer provided less than desirable due to its not reporting the first line. I found the other answers with join's too complex. I distilled the problem into this snippet
Here is the code which uses a CTE, creates a sequence within the CTE's select which identifies a row number by an ordered timestamp. The resulting selection picks on the resulting ordered rows and determines minutes.
WITH AgentActions AS
(
select ROW_NUMBER() OVER (ORDER BY [TimeStamp]) -- Create an index number ordered by time.
AS [Sequence],
* from AgentInteractions
)
SELECT *,
ISNULL(DATEDIFF(Minute,
(SELECT other.TimeStamp
FROM AgentActions Other
WHERE other.Sequence = AgentActions.Sequence - 1 ),
AgentActions.TimeStamp),
0)
AS MinutesFromLastPoint
FROM AgentActions;
Here is the setup table
CREATE TABLE AgentInteractions
(
[Event] VARCHAR(12) NOT NULL,
[Timestamp] [DateTime] NOT NULL
);
INSERT INTO dbo.AgentInteractions( Event, TimeStamp )
VALUES ( 'Alpha', '1-Jan-2018 3:04:22 PM' ),
( 'Omega', '3-Jan-2018 10:04:22 PM' ),
( 'Beta', '2-Jan-2018 2:04:22 AM' );
Results
SQL Fiddle Example
This is my current version/solution:
declare #temp table
(
id int,
timestamp datetime,
type nvarchar(255),
skillname nvarchar(255),
event nvarchar(255),
userstatus nvarchar(255)
)
insert into #temp (id, timestamp, type, skillname, event, userstatus)
(
select ROW_NUMBER() over (order by timestamp) as id, * from
(
select TimeStamp, 'Event' as type, SkillName, Event, UserStatus from AgentEvents
where TimeStamp >= '2012-05-22T00:00:00'
and UserName like '%engel%'
union
select TimeStamp, 'Anruf' as type, SkillName, '' as event, '' as status from calls
where TimeStamp >= '2012-05-22T00:00:00'
and UserName like '%engel%'
) as a
)
select t1.*, DATEDIFF(second, t1.timestamp, t2.timestamp) as duration
from #temp t1
left outer join #temp t2 on t1.id = t2.id - 1
Edit: changed inner join to left outer join, otherwise the last row would be lost.
As I understand it, you need to update the duration column.
You can use something like this :
update mytable a set duration = DateDiff( a.timestamp, select top b.timestamp from mytable b order by b.timestamp asc)
I cannot test it, but just to give you an idea (it may have some syntax errors).
Using the 'top' with the 'order by' clause should do the trick.
(Edited)
I think you better create a trigger
CREATE TRIGGER update_duration ON sometable
INSTEAD OF INSERT
AS
DECLARE #lastDT datetime
BEGIN
SET #lastDT =
(SELECT TOP 1 _timestamp
FROM sometable
ORDER BY _timestamp DESC)
UPDATE sometable
SET duration = DATEDIFF(MINUTE, #lastDT, GETDATE())
END
WITH rows AS
(
SELECT *, ROW_NUMBER() OVER (ORDER BY Col1) AS rn
FROM dbo.Table_2
)
SELECT mc.col1, DATEDIFF(HOUR, mc.Col1, mp.Col1) as TimeDiffInHours
FROM rows mc
JOIN rows mp
ON mc.rn = mp.rn-1

Resources