Need Help Using Update statement in a CTE - sql

I created a CTE to create a Flag=1 for each IndividualID where the A1.InfantSum > A2.InfantSum and the query works the way it should:
WITH ATQInfant_CTE AS
(
SELECT
*,
ROW_NUMBER() OVER (PARTITION BY ATQInfant_IndividualID ORDER BY ATQInfant_CreateDate) AS rownum
FROM
[dbo].[vCDCP_rptInfantImprove]
)
SELECT DISTINCT
A1.ATQInfant_IndividualID,
A1.ATQInfant_CreateDate,
A1.InfantSum,
A2.InfantSum,
CASE
WHEN A1.InfantSum > A2.InfantSum THEN 1 ELSE 0
END AS flag
FROM
ATQInfant_CTE AS A1
INNER JOIN
ATQInfant_CTE AS A2 ON A1.ATQInfant_IndividualID = A2.ATQInfant_IndividualID
AND A1.rownum = A2.rownum + 1
I get the following result, but need to have the Flag=0 if the IndividualID has more than one '1'.
I'm not sure how to incorporate the Update part to the query so that I can set the Flag to 0 if the IndividualID has more than one '1' in the flag. When I add the Update query to the end, it does not recognize 'Flag' as a column name in the query: Can someone let me know how I can add the Update query to the CTE?
UPDATE [dbo].[vCDCP_rptInfantImprove]
SET flag = '0'
WHERE flag = 1 AND a2.rownum + 1 > 1
What the new query results look like:

THis query will give you the rows that are not the latest occurence of ATQInfant_IndividualID
Select * from [dbo].[vCDCP_rptInfantImprove] a
where exists(select 1 from [dbo].[vCDCP_rptInfantImprove] b where a.ATQInfant_IndividualID = b.ATQInfant_IndividualID a.ATQInfant_CreateDate < b.ATQInfant_CreateDate)
if those are the ones you want to flag to zero, do:
update a
set flag = '0'
from [dbo].[vCDCP_rptInfantImprove] a
where exists(select 1 from [dbo].[vCDCP_rptInfantImprove] b where a.ATQInfant_IndividualID = b.ATQInfant_IndividualID a.ATQInfant_CreateDate < b.ATQInfant_CreateDate)
Adjustement of first query:
THe flag is 1 only if it doesnt exist a line with the same ATQInfant_IndividualID that is not more recent.
Let us know
WITH ATQInfant_CTE AS
(
SELECT
*,
ROW_NUMBER() OVER (PARTITION BY ATQInfant_IndividualID ORDER BY ATQInfant_CreateDate) AS rownum
FROM
[dbo].[vCDCP_rptInfantImprove]
)
SELECT DISTINCT
A1.ATQInfant_IndividualID,
A1.ATQInfant_CreateDate,
A1.InfantSum,
A2.InfantSum,
CASE
WHEN
A1.InfantSum > A2.InfantSum and
not exists(select 1 from ATQInfant_CTE A3 where A1.ATQInfant_IndividualID = A3.ATQInfant_IndividualID and A1.ATQInfant_CreateDate < A3.ATQInfant_CreateDate) THEN 1 ELSE 0
END AS flag
FROM
ATQInfant_CTE AS A1
INNER JOIN
ATQInfant_CTE AS A2 ON A1.ATQInfant_IndividualID = A2.ATQInfant_IndividualID
AND A1.rownum = A2.rownum + 1

Related

CASE or IF statement in WHERE clause

How can I use CASE statement or IF statement in WHERE clause ?
I am trying to apply a check on the basis of COUNT
SELECT * FROM sometable
WHERE CASE WHEN (SELECT COUNT(*) FROM sometable s WHERE SP = 2 AND sometable.id = s.id) > 2 THEN sometable.SP IS NOT NULL END
So basically if the count of rows is more than 1 it should apply IS NOT NULL condition else it should not.
Your logic suggests something like:
SELECT s.*
FROM (SELECT s.*,
SUM(CASE WHEN sp = 2 THEN 1 ELSE 0 END) OVER (PARTITION BY id) as cnt_2
FROM sometable s
) s
WHERE cnt_2 <= 2 OR s.sp is not null;
That seems equivalent. The logic doesn't seem particularly useful though.

Get single row depending of conditional

I have a simple select query with some joins like:
SELECT
[c].[column1]
, [c].[column2]
FROM [Customer] AS [c]
INNER JOIN ...
So I do a left join with my principal table as:
LEFT JOIN [Communication] AS [com] ON [c].[CustomerGuid] = [com].[ComGuid]
this relatioship its 1 to *, one customer can have multiple communications
So in my select I want to get value 1 or 2 depending of condition:
Condition:
if ComTypeKey (from communication) table have a row with value 3 and have another row with vale 4 return 1 then 0
So I try something like:
SELECT
[c].[column1]
, [c].[column2]
, IIF([com].[ComTypeKey] = 3 AND [com].[ComTypeKey] = 4,1,0)
FROM [Customer] AS [c]
INNER JOIN ...
LEFT JOIN [Communication] AS [com] ON [c].[CustomerGuid] = [com].[ComGuid]
But it throws me two rows, beacause there are 2 rows on communication. My desire value is to get only one row with value 1 if my condition is true
If you have multiple rows you need GROUP BY, then count the relevant keys and subtract 1 to get (1, 0)
SELECT
[c].[column1]
, [c].[column2]
, COUNT(CASE WHEN [ComTypeKey] IN (3,4) THEN 1 END) - 1 as FLAG_CONDITION
FROM [Customer] AS [c]
INNER JOIN ...
LEFT JOIN [Communication] AS [com]
ON [c].[CustomerGuid] = [com].[ComGuid]
GROUP BY
[c].[column1]
, [c].[column2]
I'm not really sure I understand.
This will literally find if both values 3 and 4 exist for that CustomerGuid, and only select one of them in that case - not filtering out any record otherwise.
If this is not what you want, providing sample data with the expected result would remove the ambiguity.
SELECT Field1,
Field2,
...
FieldN
FROM (SELECT TMP.*,
CASE WHEN hasBothValues = 1 THEN
ROW_NUMBER() OVER ( PARTITION BY CustomerGuid ORDER BY 1 )
ELSE 1
END AS iterim_rn
FROM (SELECT TD.*,
MAX(CASE WHEN Value1 = '3' THEN 1 ELSE 0 END) OVER
( PARTITION BY CustomerGuid ) *
MAX(CASE WHEN Value1 = '4' THEN 1 ELSE 0 END) OVER
( PARTITION BY CustomerGuid ) AS hasBothValues
FROM TEST_DATA TD
) TMP
) TMP2
WHERE interim_rn = 1

Select the records that have some value but at the same time have not other value

Before starting, thank you for your help.
My problem is: I have a table, for example, activity_records, that has a date column and a activity_id column.
I want to select only those dates that, for example, have the activity_id value of 1 but do not have the value of 2 in any of the other records having the same date.
I have tried multi-select queries and all that.
One method uses not exists:
select ar.*
from activity_records ar
where ar.activity_id = 1 and
not exists (select 1
from activity_records ar2
where r2.date = ar.date and ar2.activity_id = 2
);
Because you only want dates, an alternative is group by:
select ar.date
from activity_records ar
group by ar.date
having sum(case when ar.activity_id = 1 then 1 else 0 end) > 0 and
sum(case when ar.activity_id = 2 then 1 else 0 end) = 0;
Or, most simply for this particular case:
select ar.date
from activity_records ar
where ar.activity_id in (1, 2)
group by ar.date
having max(ar.activity_id) = 1 ;
SELECT [date] FROM [activity_records] WHERE [activity_id] = 1
EXCEPT
SELECT [date] FROM [activity_records] WHERE [activity_id] = 2
See also WHERE NOT EXISTS and APPLY for more complicated scenarios.
Another way is to take only those dates with one distinct activity_id against it and then filtering those dates with activity_id = 1 by a self join.
SELECT DISTINCT B.DATE
FROM
(SELECT DATE, COUNT(DISTINCT ACTIVITY) AS COUNT_ACTIVITIES
FROM YOUR_TABLE
GROUP BY DATE
HAVING COUNT(DISTINCT ACTIVITY) = 1) A
INNER JOIN
YOUR_TABLE B
ON A.DATE = B.DATE
AND B.ACTIVITY_ID = 1;
One method using not in :
select ar.* from activity_records ar where ar.activity_id = 1 and ar.date not in (select ar2.date from activity_records ar2 where ar2.activity_id = 2 );

Sql server aggregate function and GROUP BY Clause error

I have a query below where it compares the number of stagingCabincrew and StagingCockpitCrew columns from the staging schema and compares them to their data schema equivalent 'DataCabinCrew' and 'DataCockpitCrew'.
Below is the query and the results outputted:
WITH CTE AS
(SELECT cd.*,
c.*,
DataFlight,
l.ScheduledDepartureDate,
l.ScheduledDepartureAirport
FROM
(SELECT *,
ROW_NUMBER() OVER(PARTITION BY LegKey
ORDER BY UpdateID DESC) AS RowNumber
FROM Data.Crew) c
INNER JOIN Data.CrewDetail cd ON c.UpdateID = cd.CrewUpdateID
AND cd.IsPassive = 1
AND RowNumber = 1
INNER JOIN
(SELECT *,
Carrier + CAST(FlightNumber AS VARCHAR) + Suffix AS DataFlight
FROM Data.Leg) l ON c.LegKey = l.LegKey )
SELECT StagingFlight,
sac.DepartureDate,
sac.DepartureAirport,
cte.DataFlight,
cte.ScheduledDepartureDate,
cte.ScheduledDepartureAirport,
SUM(CASE
WHEN sac.CREWTYPE = 'F' THEN 1
ELSE 0
END) AS StagingCabinCrew,
SUM(CASE
WHEN sac.CREWTYPE = 'C' THEN 1
ELSE 0
END) AS StagingCockpitCrew,
SUM(CASE
WHEN cte.CrewType = 'F' THEN 1
ELSE 0
END) AS DataCabinCrew,
SUM(CASE
WHEN cte.CrewType = 'C' THEN 1
ELSE 0
END) AS DataCockpitCrew
FROM
(SELECT *,
Airline + CAST(FlightNumber AS VARCHAR) + Suffix AS StagingFlight,
ROW_NUMBER() OVER(PARTITION BY Airline + CAST(FlightNumber AS VARCHAR) + Suffix
ORDER BY UpdateId DESC) AS StageRowNumber
FROM Staging.SabreAssignedCrew) sac
LEFT JOIN CTE cte ON StagingFlight = DataFlight
AND sac.DepartureDate = cte.ScheduledDepartureDate
AND sac.DepartureAirport = cte.ScheduledDepartureAirport
AND sac.CREWTYPE = cte.CrewType
WHERE MONTH(sac.DepartureDate) + YEAR(sac.DepartureDate) = MONTH(GETDATE()) + YEAR(GETDATE())
AND StageRowNumber = 1 --AND cte.ScheduledDepartureDate IS NOT NULL
--AND cte.ScheduledDepartureAirport IS NOT NULL
GROUP BY StagingFlight,
sac.DepartureDate,
sac.DepartureAirport,
cte.DataFlight,
cte.ScheduledDepartureDate,
cte.ScheduledDepartureAirport
The results are correct, all I need to do is add a condition in the WHERE clause where StagingCabinCrew <> DataCabinCrew AND StagingCockpitCrew <> DataCockpitCrew
If a row appears then we have found an error in the data, I just need helping adding this condition in the WHERE Clause because the columns in the WHERE Clause are referring to a SUM and CASE Function. I just need help manipulating the query so that I can add this WHERE Clause
I will guess you are trying to use an alias in the same query.
You CANT do this, because the alias wont be recognized in the WHERE.
SELECT field1 + field2 as myField
FROM yourTable
WHERE myField > 3
You need to include it in a sub query
with cte2 as (
SELECT field1 + field2 as myField
FROM yourTable
)
SELECT *
FROM cte2
WHERE myField > 3
or repeat the function
SELECT field1 + field2 as myField
FROM yourTable
WHERE field1 + field2 > 3

Joining 2 queries...error while pulling certain fields out

I am trying to join 2 queries & get certain columns out of the join. But I am getting an error. Can you please help me understand where I am going wrong -
SELECT X.*,Y.* FROM
(
(
SELECT
C1,C2,C3
COUNT(C4) AS CNT -- count
FROM [dbo].[Tb1]
WHERE C1 <> 0 AND -- amount not = zero
C2 = 'F' -- flag
GROUP BY C1,C2,C3
HAVING COUNT(C4) > 1
)X
INNER JOIN
(SELECT * FROM [dbo].[Tb1])Y
ON
X.C1 = Y.C1
AND X.C2 = Y.C2
AND X.C3=Y.C3
AND X.C4=Y.C4
)
The first query helps me get the duplicates & the second query will help me get the other fields out of the same table.
Thanks.
Solution #1:
SELECT X.*,Y.* FROM
--( <-- (1) comment this line
(
SELECT
C1,C2,C3, -- <-- (2) add , after C3
COUNT(C4) AS CNT -- count
FROM [dbo].[Tb1]
WHERE C1 <> 0 AND -- amount not = zero
C2 = 'F' -- flag
GROUP BY C1,C2,C3
HAVING COUNT(C4) > 1
)X
INNER JOIN
(SELECT * FROM [dbo].[Tb1])Y
ON
X.C1 = Y.C1
AND X.C2 = Y.C2
AND X.C3=Y.C3
AND X.CNT=Y.C4 <-- see anir's comment
--) <-- (3) comment this line
Or
Solution #2:
SELECT X.*, Y.*
FROM
(
SELECT
C1,C2,C3,
COUNT(C4) AS CNT -- count
FROM [dbo].[Tb1]
WHERE
C1 <> 0 AND -- amount not = zero
C2 = 'F' -- flag
GROUP BY C1,C2,C3
HAVING COUNT(C4) > 1
) X
INNER JOIN [dbo].[Tb1] Y
ON X.C1 = Y.C1
AND X.C2 = Y.C2
AND X.C3=Y.C3
AND X.CNT=Y.C4 <-- see anir's comment
Note #1: When CNT > 1 and x.C1 , y.C1 contains NULLs then X.C1 = Y.C1 <=> NULL = NULL which is evaluated to UNKNOWN if ANSI_NULLS is ON. This means that these rows will be eliminated from final resultset. The same applies to X.C2 = Y.C2 and X.C3=Y.C3.
SET ANSI_NULLS ON
SELECT CASE WHEN NULL = NULL THEN 1 ELSE 0 END AS T1
SET ANSI_NULLS OFF
SELECT CASE WHEN NULL = NULL THEN 1 ELSE 0 END AS T2
/*
T1
-----------
0
T2
-----------
1
*/
Note #2: "In a future version of SQL Server, ANSI_NULLS will always be ON and any applications that explicitly set the option to OFF will generate an error.".
Or
Solution #3:
SELECT y.*
FROM
(
SELECT x.*, COUNT(x.C4) OVER(PARTITION BY x.C1, x.C2, x.C3) AS CNT -- count
FROM [dbo].[Tb1] x
WHERE
x.C1 <> 0 AND -- amount not = zero
x.C2 = 'F' -- flag
-- AND x.C1 IS NOT NULL AND x.C2 IS NOT NULL AND x.C3 IS NOT NULL ?
) y
WHERE y.CNT > 1 AND y.CNT = y.C4