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

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

Related

Oracle Query to get single result depending on values in result set

WITH T1 AS SELECT DISTINCT(DETAILS) FROM ( SELECT STATUS, PREREQUISITE_NM,
(case when (STATUS='Completed' ) then 'Completed'
when (STATUS='Pending' ) then 'Pending'
when (STATUS='Failed' and PREREQUISITE_NM = 'Y') then 'Failed'
when (STATUS='Failed' and PREREQUISITE_NM = 'N') then 'Completed'
end )DETAILS FROM TABLE_LIST WHERE ID=1))
T2 AS ( SELECT DETAILS FROM T1)
Result 1 :
Pending
Failed
Completed.
Result 2:
Failed
Completed.
In above Query we see the different result set as per data available. I want to write a query in T2 Block which should give Output as :
for Pending/Failed/Completed : should give Pending as output.
For Failed/Completed : should give Failed as Output.
Is it possible to achieve this through query without using PL SQL block. like using WITH clause?
I can explain my aim such as
Lets say T1 Block is giving me result as three rows Pending,Failed, Completed then I want Pending as a Output value. If T1 Block is giving me result as Failed, Completed then I want to Failed as Output value. If T1 block is giving only Completed then Completed will be considered as a output value.
Thanks Roberto and Barbaros Ozhan, Both Answers were useful.Posting another way shared by one of my colleague.
WITH T1 AS (
SELECT
DISTINCT(DETAILS)
FROM (
SELECT STATUS, PREREQUISITE_NM,
(
CASE
WHEN (STATUS = 'Failed' ) THEN
CASE WHEN PREREQUISITE_NM = 'Y' THEN 'Failed'
WHEN PREREQUISITE_NM = 'N' THEN 'Completed'
END
ELSE
STATUS
END
)DETAILS FROM TABLE_lIST WHERE ID=1)
),
T2 AS
(
SELECT CASE
WHEN EXISTS
( SELECT DETAILS FROM T1 where DETAILS='Pending' )
THEN 'Pending'
WHEN EXISTS
( SELECT DETAILS FROM T1 WHERE DETAILS='InProgress' )
THEN 'InProgress'
WHEN EXISTS
(SELECT DETAILS FROM T1 where DETAILS='Failed' )
THEN 'Failed'
ELSE 'Completed' END as DETAILS from DUAL
)SELECT * FROM T2
You can use ROW_NUMBER() Analytic function to bring those status values in alphabetical order descendingly which would suite your need :
WITH T1 AS
(
SELECT DISTINCT (CASE
WHEN (STATUS = 'Failed' ) THEN
CASE WHEN PREREQUISITE_NM = 'Y' THEN 'Failed'
WHEN PREREQUISITE_NM = 'N' THEN 'Completed'
END
ELSE
STATUS
END) AS details
FROM TABLE_LIST
WHERE ID = 1
), T2 AS
(
SELECT T1.*, ROW_NUMBER() OVER (ORDER BY details DESC) AS rn
FROM T1
)
SELECT details
FROM T2
WHERE rn = 1
After reading your comments, I came up with this solution, that perhaps is not the best, but at the end gives the output you expect , based on that what you actually want is to transpose the rows produced in t1 to columns in t2
I used my own test, please be aware to replace the columns or modify whatever is necessary to adapt it to your own query
SQL> desc my_test
Name Null? Type
----------------------------------------- -------- ----------------------------
C1 NUMBER
C2 VARCHAR2(20)
C3 VARCHAR2(1)
SQL> select * from my_test ;
C1 C2 C3
---------- -------------------- -
1 Failed Y
2 Completed Y
1 Pending Y
1 Pending N
SQL>
So, If just got the first part of my query
SQL> WITH T1 AS (
SELECT DISTINCT c2 FROM ( SELECT c1,c2,
case when c2='Completed' then 'Completed'
when c2='Pending' then 'Pending'
when c2='Failed' and c3 = 'Y' then 'Failed'
when c2='Failed' and c3 = 'N' then 'Completed'
else c2
end FROM my_test WHERE c1=1
) )
select trim ( completed || ' ' || failed || ' ' || pending ) as result
from
(
select * from t1 pivot ( max(c2) for c2 in ( 'Completed' as Completed, 'Failed' as Failed, 'Pending' as Pending ) )
)
/ 9 10 11 12 13 14 15
RESULT
--------------------------------------------------------------
Failed Pending
Now I only need to build a case over that result ( modify it to your own requirements )
SQL> WITH T1 AS (
SELECT DISTINCT c2 FROM ( SELECT c1,c2,
case when c2='Completed' then 'Completed'
when c2='Pending' then 'Pending'
when c2='Failed' and c3 = 'Y' then 'Failed'
when c2='Failed' and c3 = 'N' then 'Completed'
else c2
end FROM my_test WHERE c1=1
) )
select
case when result = 'Completed Failed Pending' then 'Pending'
when result = 'Completed Failed' then 'Failed'
when result = 'Failed Pending' then 'Failed' -- I guess
when result = 'Completed Pending' then 'Pending' -- I guess
end as output
from (
select trim ( completed || ' ' || failed || ' ' || pending ) as result
from
(
select * from t1 pivot ( max(c2) for c2 in ( 'Completed' as Completed, 'Failed' as Failed, 'Pending' as Pending ) )
)
)
/
OUTPUT
-------
Failed
SQL>

Need Help Using Update statement in a CTE

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

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

SQL Server 2008, how to count distinct values that change

I have entities that have 2 answers y/n.
I need to count the number of entities who change answers from 'n' to 'y' between stage1 and stage2.
entity || answer || stage
a || y || 1
a || n || 2
b || y || 1
b || y || 2
c || n || 1
c || n || 1
d || n || 1
d || y || 2
I tried this but this doesn't work (because it counts all entities who change answers)
select
entity, count(distinct answer)
from
myDB
where
stage between '1' and '2'
group by
entity, answer
but I don't understand why this doesn't work, the result comes out all O's
select
entity,
case
when stage = '1' and answer = 'n' and
stage = '2' and answer = 'y' then 1
else 0
end as 'result'
from
myDB
where
stage between '1' and '2'
group by
entity, stage, answer
select count(*)
from myDB s2
where
s2.stage ='2' and s2.answer='y'
and exists (select * from myDB s1
where s1.entity=s2.entity
and s1.stage ='1' and s1.answer='n'
)
select
count(*)
from
[myDb] as [s1]
inner join
[myDb] as [s2]
on
[s1].[entity] = [s2].[entity]
and [s1].[answer] = 'n'
and [s1].[stage] = 1
and [s2].[answer] = 'y'
and [s2].[stage] = 2;
But, it works with your provided data only.
If your have duplicated enities, it does not works, because at this case there is not impossible to identify uniqueness of entity. You need additional data then.
a y 1
a n 2
b y 1
b y 2
c n 1
c n 2
d n 1
d y 2
d n 1
d y 2
Lets make assumption, that same logical entity values are stored one after another. Then you can handle this by using this query:
declare #myDB TABLE
(
[rec_id] int identity(1, 1)
,[entity] varchar(10)
,[answer] varchar(10)
,[stage] int
);
insert into #myDB
(
[entity]
,[answer]
,[stage]
)
select
[entity]
,[answer]
,[stage]
from
[myDB];
select
[s1].[entity]
,count([s1].[entity])
from
#myDB as [s1]
inner join
#myDB as [s2]
on
[s1].[entity] = [s2].[entity]
and [s1].[answer] = 'n'
and [s1].[stage] = 1
and [s2].[answer] = 'y'
and [s2].[stage] = 2
and [s1].[rec_id] = [s2].[rec_id] - 1
group by
[s1].[entity];
select count(*)
from (select entity,stage,answer from myDB) t
pivot (max(answer) for stage in([1],[2])) p
where [1] = 'n' and [2] = 'y'
select count(*)
from (select 1 as x
from myDB
where stage in (1,2)
group by entity
having min(case when stage = 1 then answer end) = 'n'
and max(case when stage = 2 then answer end) = 'y'
) t

Returning only id's of records that meet criteria

I need to return distinct ID's of records which meet following conditions :
must have records with field reason_of_creation = 1
and must NOT have records with field reason_of_creation = 0 or null
in the same time.
While i was able to do it, i keep wondering is there more elegant (even recommended) way of doing it.
Here is anonymized version of what i have :
select distinct st.some_id from (
select st.some_id, wanted.wanted_count as wanted, unwanted.unwanted_count as unwanted
from some_table st
left join (
select st.some_id, count(st.reason_of_creation) as wanted_count
from some_table st
where st.reason_of_creation=1
group by st.some_id
) wanted on wanted.some_id = st.some_id
left join (
select st.some_id, count(st.reason_of_creation) as unwanted_count
from some_table st
where st.reason_of_creation=0
group by st.some_id
) unwanted on unwanted.some_id = st.some_id
where wanted.wanted_count >0 and (unwanted.unwanted_count = 0 or unwanted.unwanted_count is null)
) st;
Sample data :
some_id reason_of_creation
1 1
1 0
2 1
3 null
4 0
4 1
5 1
desired result would be list of records with some_id = 2, 5
It seems to me your query is overkill,all you need is some post aggregation filtering
SELECT some_id FROM t
GROUP BY some_id
HAVING SUM(CASE WHEN reason_of_creation = 1 THEN 1 ELSE 0 END)>0
AND SUM(CASE WHEN reason_of_creation = 0 OR reason_of_creation IS NULL THEN 1 ELSE 0 END)=0
I think that more elegant query exists and it is based on assumption what reasoson_of_crdeation field is integer, so minimal possible it's value, which greater than 0 is 1
This is for possible negative values for reasoson_of_crdeation:
select someid from st
where reasoson_of_crdeation != -1
group by someid
having(min(nvl(abs(reasoson_of_crdeation), 0)) = 1)
or
select someid from st
group by someid
having(min(nvl(abs(case when reasoson_of_crdeation = -1 then -2 else reasoson_of_crdeation end), 0)) = 1)
And this one in a case if reasoson_of_crdeation is non-negative integer:
select someid from st
group by someid
having(min(nvl(reasoson_of_crdeation, 0)) = 1)