SQL Server Date Comparison issue - sql

I am trying to flag a field in a different table whenever two dates do not have the right relationship. However, All dates in the dataset should not flag anything(should be 0 instead of 1), but they all flag. Could it be an issue with the date format changing during the query? Really stuck here
Example output
UPDATE Theatre_DQ_03_Integrity_CASES
SET AnaesToTheatreFlag = 1, TimeErrorFlag = 1
FROM Theatre_Cases_Landing a
INNER JOIN
(
SELECT Case_ID
FROM Theatre_Cases_Landing
WHERE (CaseCancelled IS NULL or CaseCancelled = 'N') AND (CONVERT(datetime,Anaesthetic_Start_DateTime) > CONVERT(datetime,In_Theatre_DateTime))
AND Anaesthetic_Start_DateTime IS NOT NULL AND In_Theatre_DateTime IS NOT NULL
) b
ON a.Case_ID = b.Case_ID
declare #var1 as datetime2 = '2019-09-04 11:12:00.000'
declare #var2 as datetime2 = '2019-09-04 11:13:00.000'
if #var1 < #var2 PRINT('TRUE')

You need to correlate rows to be updated with the rows from the other table. Otherwise, every row in the target will be updated.
I don't see a need to self-join Theatre_Cases_Landing. Below is an untested version with the correlation.
UPDATE target
SET AnaesToTheatreFlag = 1, TimeErrorFlag = 1
FROM Theatre_DQ_03_Integrity_CASES AS target
JOIN Theatre_Cases_Landing AS a ON a.Case_ID = target.Case_ID
WHERE
(a.CaseCancelled IS NULL or a.CaseCancelled = 'N')
AND CONVERT(datetime,a.Anaesthetic_Start_DateTime) > CONVERT(datetime,a.In_Theatre_DateTime)
AND a.Anaesthetic_Start_DateTime IS NOT NULL
AND a.In_Theatre_DateTime IS NOT NULL;

Related

SQL MERGE error? [duplicate]

This question already has an answer here:
Msg 8672, Level 16, State 1, Line 1 The MERGE statement attempted to UPDATE or DELETE the same row more than once
(1 answer)
Closed 4 years ago.
Please see my below code - I am new to SQL and haven't seen this error before. Can someone advise as to where it is going wrong? The error I am getting is
(41669 row(s) affected) Msg 8672, Level 16, State 1, Line 41 The MERGE
statement attempted to UPDATE or DELETE the same row more than once.
This happens when a target row matches more than one source row. A
MERGE statement cannot UPDATE/DELETE the same row of the target table
multiple times. Refine the ON clause to ensure a target row matches at
most one source row, or use the GROUP BY clause to group the source
rows.
My code is below
DECLARE #FromDate DateTime = '31 jan 2018'
DECLARE #ToDate DateTime = '28 Feb 2018'
DECLARE #FromDate_In DateTime = #FromDate
DECLARE #ToDate_In DateTime = #ToDate
DECLARE #DirectDebit_In INT = 0
/**************************/
/* Agreement view */
/**************************/
SELECT
sag.[AgreementID]
,sca.CustomerID
,'Lost' AS [Type]
INTO #AgreementSet
FROM Money.dbo.[Fin_SS_TblAgreements] sag WITH (NOLOCK)
INNER JOIN Money.dbo.[Fin_SS_TblCustomersAgreements] [sca] WITH (NOLOCK) ON sca.DealID = sag.DealID AND sca.IsMasterCustomer = 1 AND sca.[SnapShot] = sag.[SnapShot]
INNER JOIN (
SELECT
sps.DealID
FROM Money.dbo.[Fin_SS_TblPaymentSchedule] sps WITH (NOLOCK, INDEX(IX_NC_Snapshot))
WHERE sps.[SnapShot] = #FromDate_In
GROUP BY sps.DealID
) sps ON sag.DealID = sps.DealID
WHERE sag.[SnapShot] = #FromDate_In
AND (sag.AgreementID IS NOT NULL)
AND ((sag.EndDate > sag.[SnapShot]) OR (sag.EndDate = sag.[SnapShot] AND sag.Autorenew = 1))
AND (sag.AgreementStartsOn <= sag.[SnapShot])
AND ( (#DirectDebit_In = 0 AND sag.ContractTypeID <> 3) OR (#DirectDebit_In = 1 AND sag.ContractTypeID = 3) OR (#DirectDebit_In = 3) )
DECLARE #MaxAgIDFrom INT
SELECT #MaxAgIDFrom = MAX(AgreementID) FROM Money.dbo.[Fin_SS_TblAgreements] WHERE [SnapShot] = #FromDate_In
DECLARE #MaxCIDFrom INT
SELECT #MaxCIDFrom = MAX(CustomerID) FROM #AgreementSet
MERGE INTO #AgreementSet L
USING (
SELECT
sag.[AgreementID]
,sca.CustomerID
,'New' AS [Type]
FROM Money.dbo.[Fin_SS_TblAgreements] sag WITH (NOLOCK)
INNER JOIN Money.dbo.[Fin_SS_TblCustomersAgreements] [sca] WITH (NOLOCK) ON sca.DealID = sag.DealID AND sca.IsMasterCustomer = 1 AND sca.[SnapShot] = sag.[SnapShot]
INNER JOIN (
SELECT
sps.DealID
FROM Money.dbo.[Fin_SS_TblPaymentSchedule] sps WITH (NOLOCK, INDEX(IX_NC_Snapshot))
WHERE sps.[SnapShot] = #ToDate_In
GROUP BY sps.DealID
) sps ON sag.DealID = sps.DealID
WHERE sag.[SnapShot] = #ToDate_In
AND (sag.AgreementID IS NOT NULL)
AND ((sag.EndDate > sag.[SnapShot]) OR (sag.EndDate = sag.[SnapShot] AND sag.Autorenew = 1))
AND (sag.AgreementStartsOn <= sag.[SnapShot])
AND ( (#DirectDebit_In = 0 AND sag.ContractTypeID <> 3) OR (#DirectDebit_In = 1 AND sag.ContractTypeID = 3) OR (#DirectDebit_In = 3) )
) N
ON L.AgreementID = N.AgreementID
WHEN MATCHED THEN
UPDATE SET [Type] =
CASE WHEN L.CustomerID = n.CustomerID THEN 'B/F'
ELSE 'Swap'
END
WHEN NOT MATCHED THEN
INSERT (AgreementID, CustomerID, [Type])
VALUES (n.AgreementID, n.CustomerID, n.[Type])
We get this very often.
This happens because of unique column that is being used in more than one row.
In your case this may be because of same agreementid for two or more different customers.
Check the data again and perform the same operation again.

Is there any way to restrict the data inserted into table if it is already present?

I have an sp which when triggered, data will be inserted into the data table. If the data being inserted is already present in the table, I don't want the data to be inserted into the table. is there anyway i could use a logic to restrict the data into table.
my query is
declare #ident int = IDENT_CURRENT( 'SADEV.RO_Transcript.ETQueueCtrl' )
insert into SADEV.RO_Transcript.ETQueueCtrl ([STU_ID],[STU_ORD_SEQ_NUM],[CreatedDate],[LastUpdatedDate],[ETQueueCtrlStatusCd],[ErrorFl])
select STU_ID
,STU_ORD_SEQ_NUM
,getdate()
,getdate()
,[ETQueueCtrlStatusCd] = 'N'
,'N'
from srdb_sr2_qa.dbo.SR0ROT rt
where STU_ORD_TYP_CD = 'A'
and ORD_DLVY_MTHD_CD = 'ET'
and STU_ORD_STAT_CD = 'C'
--and convert(varchar(1),STU_ORD_XPDT_FL) = #stu_ord_xpdt_fl
and case when #stu_ord_xpdt_fl = 'y' then GETDATE()
else case when ORD_PEND_INST_CD = '' then STU_ORD_SBM_DT+ DATEADD (mi,480,STU_ORD_SBM_TM)
else LAST_UPD_DT+ DATEADD (mi,480,LAST_UPD_TM)
end
end <= GETDATE()
select et.ETQueueCtrlID,
ro.STU_ID,
ro.STU_ORD_SEQ_NUM,
ty.CAREER_CD,
ty.CAREER_SUFX_CD
from SADEV.RO_Transcript.ETQueueCtrl et join srdb_sr2_qa.dbo.SR0ROT ro on et.STU_ID = ro.STU_ID
and et.STU_ORD_SEQ_NUM = ro.STU_ORD_SEQ_NUM
left join srdb_sr2_qa.dbo.SR0TYT ty on ro.STU_ID = ty.STU_ID
where et.ETQueueCtrlID > #ident
Could you add something like the below into the WHERE clause for the Insert?
AND
NOT EXISTS
(SELECT *
FROM sadev.ro_transcript.etqueuectrl AS trg
WHERE
rt.stu_id = trg.stu_id
AND
rt.stu_ord_seq_num = trg.stu_ord_seq_num)
You can adjust the above to filter out those data columns that shouldn't be duplicated

I need to optimize my first T-SQL update trigger

How do I rewrite this update trigger without using a lot of variables?
I wrote my first SQL Server trigger and it works fine, but I think, that there must be an easier solution.
If minimum one of 5 columns is changed I write two new rows in another table.
row 1 = old Fahrer (=Driver) and old dispodate and update-time
row 2 = new Fahrer and new dispodate and updatedatetime
My solution is just a copy of the foxpro-trigger, but there must be a easier solutions in T-SQL to check whether one colum is changed.
ALTER TRIGGER [dbo].[MyTrigger]
ON [dbo].[tbldisposaetze]
AFTER UPDATE
AS
SET NOCOUNT ON;
/*SET XACT_ABORT ON
SET ARITHABORT ON
*/
DECLARE #oldfahrer varchar(10)
DECLARE #oldbus varchar(10)
DECLARE #olddispodat date
DECLARE #oldvzeit decimal(4,0)
DECLARE #oldbzeit decimal(4,0)
DECLARE #oldbeschreibk varchar(255)
DECLARE #newfahrer varchar(10)
DECLARE #newbus varchar(10)
DECLARE #newdispodat date
DECLARE #newvzeit decimal(4,0)
DECLARE #newbzeit decimal(4,0)
DECLARE #newbeschreibk varchar(255)
SELECT #oldfahrer = fahrer,#oldbeschreibk=beschreibk,#oldbus=bus,#oldbzeit=bzeit,#olddispodat=dispodat,#oldvzeit=vzeit
FROM DELETED D
SELECT #newfahrer = fahrer,#newbeschreibk=beschreibk,#newbus=bus,#newbzeit=bzeit,#newdispodat=dispodat,#newvzeit=vzeit
FROM inserted I
if #oldbeschreibk <> #newbeschreibk or #oldbus <> #newbus or #oldbzeit <> #newbzeit or #oldfahrer <> #newfahrer or #oldvzeit <> #newvzeit
begin
IF (SELECT COUNT(*) FROM tbldispofahrer where fahrer=#oldfahrer and dispodat=#olddispodat) > 0
update tbldispofahrer set laenderung = GETDATE() where fahrer=#oldfahrer and dispodat=#olddispodat
else
INSERT into tbldispofahrer (fahrer,dispodat,laenderung) VALUES (#oldfahrer,#olddispodat,getdate())
IF (SELECT COUNT(*) FROM tbldispofahrer where fahrer=#newfahrer and dispodat=#newdispodat) > 0
update tbldispofahrer set laenderung = GETDATE() where fahrer=#newfahrer and dispodat=#newdispodat
else
INSERT into tbldispofahrer (fahrer,dispodat,laenderung) VALUES (#newfahrer,#newdispodat,getdate())
end
I'll assume you have SQL Server 2008 or greater. You can do this all in one statement without any variables.
Instead of doing all the work to first get the variables and see if they don't match, you can easily do that in as part of where clause. As folks have said in the comments, you can have multiple rows as part of inserted and deleted. In order to make sure you're working with the same updated row, you need to match by the primary key.
In order to insert or update the row, I'm using a MERGE statement. The source of the merge is a union with the where clause above, the top table in the union has the older fahrer, and the bottom has the new farher. Just like your inner IFs, existing rows are matched on farher and dispodat, and inserted or updated appropriately.
One thing I noticed, is that in your example newfahrer and oldfahrer could be exactly the same, so that only one insert or update should occur (i.e. if only bzeit was different). The union should prevent duplicate data from trying to get inserted. I do believe merge will error if there was.
MERGE tbldispofahrer AS tgt
USING (
SELECT d.farher, d.dispodat, GETDATE() [laenderung]
INNER JOIN inserted i ON i.PrimaryKey = d.PrimaryKey
AND (i.fahrer <> d.fahrer OR i.beschreibk <> d.beschreik ... )
UNION
SELECT i.farher, i.dispodat, GETDATE() [laenderung]
INNER JOIN inserted i ON i.PrimaryKey = d.PrimaryKey
AND (i.fahrer <> d.fahrer OR i.beschreibk <> d.beschreik ... )
) AS src (farher, dispodat, laenderung)
ON tgt.farher = src.farher AND tgt.dispodat = src.dispodat
WHEN MATCHED THEN UPDATE SET
laenderung = GETDATE()
WHEN NOT MATCHED THEN
INSERT (fahrer,dispodat,laenderung)
VALUES (src.fahrer, src.dispodat, src.laenderung)
There were a few little syntax errors in the answer from Daniel.
The following code is running fine:
MERGE tbldispofahrer AS tgt
USING (
SELECT d.fahrer, d.dispodat, GETDATE() [laenderung] from deleted d
INNER JOIN inserted i ON i.satznr = d.satznr
AND (i.fahrer <> d.fahrer OR i.beschreibk <> d.beschreibk or i.bus <> d.bus or i.bzeit <> d.bzeit or i.vzeit <> d.vzeit)
UNION
SELECT i.fahrer, i.dispodat, GETDATE() [laenderung] from inserted i
INNER JOIN deleted d ON i.satznr = d.satznr
AND (i.fahrer <> d.fahrer OR i.beschreibk <> d.beschreibk or i.bus <> d.bus or i.bzeit <> d.bzeit or i.vzeit <> d.vzeit)
) AS src (fahrer, dispodat, laenderung)
ON tgt.fahrer = src.fahrer AND tgt.dispodat = src.dispodat
WHEN MATCHED THEN UPDATE SET
laenderung = GETDATE()
WHEN NOT MATCHED THEN
INSERT (fahrer,dispodat,laenderung)
VALUES (src.fahrer, src.dispodat, src.laenderung);

Are these SQL queries equivalent?

I'm quite new to SQL. The first query is "correct" but I want to rewrite it so that it returns nothing instead of "Ok". Query #2 is my try. According to me, it is correct because the JOIN condition separates all rows where the two dates are different. But I'm not sure at this and as I said I'm kind a new to this.. The problem is that I have no test-data right to cross verify. Could you please help?
1
DECLARE #date1 datetime,
#date2 datetime
SELECT #date1 = Max(date) FROM table1
WHERE 1 = 1
AND id = 1
AND id2 = 11
SELECT #date2 = Max(date) FROM table2
WHERE 1 = 1
AND id = 2
AND id2 = 11
SELECT
CASE
WHEN COALESCE(#date1,0) = #date2
THEN 'Ok'
WHEN CONVERT(TIME,GETDATE()) < '19:00:00'
THEN 'Ok'
ELSE 'Not Ok'
END AS Warning
2:
DECLARE #date1 datetime
,#date2 datetime
,#id int = 1
SELECT #date1 = COALESCE(MAX(date),0) FROM table1
WHERE 1 = 1
AND id = #id
AND id3 = 11
SELECT #date2= MAX(date) FROM table1
WHERE 1 = 1
AND id = #id
AND id2 = 11
SELECT
'Warning' = CASE WHEN CONVERT(TIME,GETDATE()) > '19:00:00'
THEN 'not ok'
END
FROM dbo.table1 AS a
INNER JOIN dbo.table AS a2 ON 1 = 1
AND #date1 != #date2
WHERE 1 = 1
AND a.nBranchId = #id
AND a.nInstrId = 11
Not nearly equivalent. In both versions, the #date1 variable will be NULL if there are no rows satisfying the conditions of the query used to initialise its value.
If that's the case, the last select from version 1 will return a single row with value being either "Ok" or "Forwardpoints missing in XP_ResultsOutRightForwards", depending on the current time.
The version 2, however, will not return any rows whatsoever because you used this variable in the condition of an inner join. The inequality does not work with NULL values, so you will receive an empty set.

SQL Stored Procedure set variables using SELECT

I have a stored procedure in SQL Server 2005 with multiple variables and I want to set the values of these variables using a select statement. All three variables come from a same table and there should be a way to set them using one select statement instead of the way I currently have as shown below. Please help me to figure it out.
DECLARE #currentTerm nvarchar(max)
DECLARE #termID int
DECLARE #endDate datetime
SET #currentTerm =
(
Select CurrentTerm from table1 where IsCurrent = 1
)
SET #termID =
(
Select TermID from table1 where IsCurrent = 1
)
SET #endDate =
(
Select EndDate from table1 where IsCurrent = 1
)
select #currentTerm = CurrentTerm, #termID = TermID, #endDate = EndDate
from table1
where IsCurrent = 1
One advantage your current approach does have is that it will raise an error if multiple rows are returned by the predicate. To reproduce that you can use.
SELECT #currentTerm = currentterm,
#termID = termid,
#endDate = enddate
FROM table1
WHERE iscurrent = 1
IF( ##ROWCOUNT <> 1 )
BEGIN
RAISERROR ('Unexpected number of matching rows',
16,
1)
RETURN
END