Are these SQL queries equivalent? - sql

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.

Related

SQL Server Date Comparison issue

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;

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.

SQL How to count all remains for each date

I have the following SQL function
CREATE FUNCTION [dbo].[GetCardDepartRemains]
(
#CardId INT,
#DepartId INT,
#Date DATETIME = NULL,
#DocumentId INT = NULL
)
RETURNS INT
AS
BEGIN
DECLARE #Res INT
SELECT
#Res = ISNULL(SUM(CASE WHEN Operations.[Output] = 0 AND Operations.RecipientId = #DepartId THEN 1 ELSE -1 END), 0)
FROM dbo.Operations
WHERE Operations.CardId = #CardId
AND (Operations.[Output] = 0 AND Operations.RecipientId = #DepartId OR Operations.Input = 0 AND Operations.SenderId = #DepartId)
AND (#Date IS NULL OR Operations.[Date] <= #Date)
RETURN #Res
END
GO
It counts remains for certain product on certain department on certain date.
If it is less then zero it means something's wrong with database
Now I need to find all remains for each card, for each department for all dates in database where result is wrong.
Theoretically speaking we can fing this by calling this procedure in a query like this
SELECT DISTINCT Operations.[Date] as [Date],
Departments.Id as Depart,
Cards.Id as [Card],
[dbo].[GetCardDepartRemains] (Cards.Id, Departments.Id,Operations.[Date],NULL) as Res
FROM [jewellery].[dbo].[Cards]
CROSS JOIN [jewellery].[dbo].[Departments]
CROSS JOIN [jewellery].[dbo].[Operations]
WHERE [dbo].[GetCardDepartRemains] (Cards.Id, Departments.Id,Operations.[Date],NULL) = -1
But this query executes more than 2 minutes, so we need to write a new query.
My query can find all remains for each card on each department on certain date (ex. '2016-10-04')
SELECT
[Card],
Depart,
Res
FROM
(SELECT
Cards.Id as [Card],
Departments.Id as Depart,
ISNULL(SUM(CASE WHEN Operations.[Output] = 0 AND Operations.RecipientId = Departments.Id THEN 1 ELSE -1 END), 0) as Res
FROM Operations
CROSS JOIN Cards
CROSS JOIN Departments
WHERE Operations.CardId = Cards.Id
AND (Operations.[Output] = 0 AND Operations.RecipientId = Departments.Id OR Operations.Input = 0 AND Operations.SenderId = Departments.Id)
AND (Operations.[Date] <= '2016-10-04')
GROUP BY Cards.Id, Departments.Id
) as X
WHERE Res = -1
Can you help to re-write this query to find remains for all dates?
Assuming SQL Server is 2008 or above:
To find all dates, just comment out the date filter like this:
-- AND (Operations.[Date] <= '2016-10-04')
If you need to filter on a date range:
AND (Operations.[Date] between between getDate()-30 and getDate()
Changing -30 to however many days in the past. So a year ago would be -364.

Looping through records

I have a table where, among others, these three columns below are included. These are ID changes saved in the DB, where an ID in this case has gone from 1->2->3->4.
oldID | newID | added
1 | 2 | 2012-11-23
2 | 3 | 2012-11-24
3 | 4 | 2012-11-25
4 | 1 | 2012-11-26
What I would like to do is to send in a oldID parameter and return the newID, stepping through the changes. So for example, if I send in 2 it returns 1.
I'm not getting anything with my SQL-query below because I don't really know what I'm doing.
DECLARE #dateCurrent datetime
DECLARE #datePrevious datetime
DECLARE #oldID int
SET #dateCurrent = '1970-01-01'
SET #datePrevious = '1970-01-01'
SET #oldID = '2'
WHILE (#dateCurrent >= #datePrevious)
BEGIN
SELECT #oldID = newID, #datePrevious = added
FROM theTable
WHERE oldID = #oldID
END
If you want to recurse, you can use common table expressions
eg:
;with cte as
(
select *, 0 as level from yourtable
union all
select t1.old, cte.new, t1.dateadded, level + 1 from yourtable t1
inner join cte on t1.new = cte.old
and t1.dateadded<cte.dateadded
)
select old, new from
(select old, new, ROW_NUMBER() over (partition by old order by level desc) rn from cte)
v
where rn=1
I agree this might not look like the best solution, but I'm not about to change something in a system that has been running since 95'.
I got it to work like this:
DECLARE #dateCurrent datetime
DECLARE #datePrevious datetime
DECLARE #oldID int
SET #dateCurrent = '1970-01-01'
SET #datePrevious = '1970-01-01'
SET #oldID = '2'
WHILE (#datePrevious <= #dateCurrent )
BEGIN
SET #datePrevious = #dateCurrent
SELECT #dateCurrent = t2.added, #oldID = t1.newID
from theTable
inner join theTable t2
on t2.oldID = t1.newID
where t1.oldID = #oldID
END
SELECT #oldID

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