Not getting desire SQL output with inner query - sql

Table-1: NominationPeriods
----------------------
Id Period Status
----------------------
1 9 Unlocked
3 8 locked
----------------------
Table-2 : NominationRevisions
-------------------------------------------
Id Revision Period Status
-------------------------------------------
15 1 9 M
19 2 9 R
20 3 9 A
--------------------------------------------
Query:
SELECT Period
,nomper.STATUS
,(
CASE
WHEN (
(
SELECT (
CASE
WHEN STATUS IN ('P','A')
THEN 'TRUE'
ELSE 'FALSE'
END
)
FROM NominationRevisions
WHERE revision = (
SELECT max(revision)
FROM NominationRevisions
WHERE Period = nomper.Period
)
AND NomPeriodNbr = nomper.Period
) = 'TRUE'
)
THEN 'TRUE'
ELSE 'FALSE'
END
) AS Flag
FROM NominationPeriods nomper
Expected Output:
-------------------------------------
Period Status Flag
-------------------------------------
9 Unlocked TRUE
8 locked TRUE
-------------------------------------
Actual Output:
-------------------------------------
Period Status Flag
-------------------------------------
9 Unlocked TRUE
-------------------------------------
I want all NominationPeriods list as output having
Highest Revision of the Period is 'A' or 'P' then Flag=TRUE
If no Revision found for a period then also return Flag=TRUE

Try this:
select "Period", "Status",
Coalesce((select top 1 case when r."Status" in ('A', 'P') then 'TRUE' else 'FALSE' end from NominationRevisions r where p.Period = r.Period order by r.Revision desc), 'TRUE') "Flag"
from NominationPeriods p
Now I believe it's OK.

I expect this might work for you, using JOIN:
SELECT
np.*,
COALESCE(
IF( nr.`Status` IS NULL, 'TRUE', NULL),
IF(nr.`Status` IN ('A', 'R'), 'TRUE', NULL),
'FALSE'
) AS 'Flag'
FROM nominationperiods np
LEFT JOIN nominationrevisions nr ON
np.Period = nr.Period
AND nr.Revision = (SELECT MAX(nr.Revision)
FROM nominationrevisions nr
WHERE nr.Period = np.Period)
The join takes max revision only, and then uses coalesce() to test all conditions for true, with a fallback to false.

I rewrited your query with less cases and in a didatic manner. See this fiddle for a working example usind the data your provided.
The point is: Return all Nomination Period but only set flag to TRUE if the last revision got an A or P status.
select nomper.Period, nomper.Status
,case when
(
exists
(
select 1
from dbo.[NominationRevisions] nr
join
(
select max(nr0.Revision) as MaxRevision, nr0.Period
from dbo.[NominationRevisions] nr0
group by nr0.Period
) as nr1 on nr1.Period = nr.Period
and nr1.MaxRevision = nr.Revision
where nr.Status = 'A' or nr.Status = 'P'
)
)
then 'TRUE'
else 'FALSE'
end
from dbo.[NominationPeriods] nomper

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>

Looking for best way to execute Yes/No Query check in select statement

I was wondering if anyone could recommend the best way to execute this. I will introduce you to what I'm working on.
I've written a select query with some sub-queries which gets order records, I have a number business logic that these orders need to meet so that they come up on the report.
Additionally I've added a nested case statement which helps me determine is the business logic is met and it simply returns a Yes or a No. So far all looks great!
E.G.
Above is just a sample result for one order (29817). What I need to do next is only show Order_No when NOYESCHECK returns all YES's.
Nested Case statement:
(case when sm.supply_code='Project Inventory' and
(select po.order_no
from purchase_order_line_all po
where po.contract = sm.contract
and po.part_no = sm.part_no
and po.activity_seq = sm.activity_seq
and po.project_id = sm.project_id
and po.state in ('Closed','Arrived','Recieved') order by po.date_entered desc fetch first 1 row only) is not null then 'YES'
when sm.supply_code='Invent Order' and
( select sum(QTY_ONHAND - QTY_RESERVED)
from inventory_part_in_stock ipis
where ipis.contract = sm.contract
and ipis.part_no = sm.part_no
and ipis.QTY_ONHAND - ipis.QTY_RESERVED > '0'
and ipis.project_id is null
and ipis.AVAILABILITY_CONTROL_ID not in ('QUARANTINE','RD','TRANSIT','PRE SCRAP')
) is not null then 'YES'
else 'NO' end)NoYesCheck
What would be the best way to achieve this? I have tried using ALL operator but it didn't work quite as expected. What I tried with ALL operator:
and 'YES' = ALL (case when sm.supply_code='Project Inventory' and
(select po.order_no
from purchase_order_line_all po
where po.contract = sm.contract
and po.part_no = sm.part_no
and po.activity_seq = sm.activity_seq
and po.project_id = sm.project_id
and po.state in ('Closed','Arrived','Recieved') order by po.date_entered desc fetch first 1 row only) is not null then 'YES'
when sm.supply_code='Invent Order' and
( select sum(QTY_ONHAND - QTY_RESERVED)
from inventory_part_in_stock ipis
where ipis.contract = sm.contract
and ipis.part_no = sm.part_no
and ipis.QTY_ONHAND - ipis.QTY_RESERVED > '0'
and ipis.AVAILABILITY_CONTROL_ID not in ('QUARANTINE','RD','TRANSIT','PRE SCRAP')
and ipis.project_id is null
) is not null then 'YES'
else 'NO' end)
It seemed to return only lines with 'YES' in my check but the purpose here is:
If check is done per order and returns at least one 'No' then do not show the order. So in above image this order was never meant to show up as a result in my query but it did. So I'm a little stuck.
Any help would be appreciated. Let me know if I need to provide more info.
Thanks,
Kasia
You can use your NOYESCHECK column in a subselect within the where clause combined with a NOT IN check.
Psuedo code:
select
--main query columns
from data_source
where key_column not in (
select distinct
key_column
from (
select
key_column,
noyescheck_column
from data_source
where noyescheck_column = 'NO'
)
)
Would this help? See comments within code.
SQL> with
2 -- this is what your query currently returns
3 test (order_no, component_part, noyescheck) as
4 (select 29817, 100, 'NO' from dual union all
5 select 29817, 101, 'YES' from dual union all
6 --
7 select 30000, 200, 'YES' from dual union all
8 select 30000, 201, 'YES' from dual union all
9 --
10 select 40000, 300, 'NO' from dual
11 ),
12 -- find ORDER_NOs whose NOYESCHECK = YES only
13 yess as
14 (select order_no
15 from test
16 group by order_no
17 having min(noyescheck) = max(noyescheck)
18 and min(noyescheck) = 'YES'
19 )
20 -- return only ORDER_NOs that satisfy condition
21 select t.*
22 from test t join yess y on y.order_no = t.order_no;
ORDER_NO COMPONENT_PART NOY
---------- -------------- ---
30000 200 YES
30000 201 YES
SQL>

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)

sql Select id that matches combination of column

I have a token table
id | status
------------
1 | taken
1 | used
1 | deleted
2 | taken
2 | deleted
3 | taken
I need to count how many tokens are used ( in use or used).
If a token is taken and deleted without being used then it should not be counted.
So sql would be sth like
SELECT count(*) if the id's status is not (taken & deleted)
The desired number of used token in above example is 2 as
id 1 has been taken used and deleted -> count it
id 3 has been taken -> count it
id 2 has been taken and deleted without being used -> do not count it
A little bit verbose but efficient and still readable and maintainable:
SELECT COUNT(DISTINCT id)
FROM dbo.Token t
WHERE EXISTS
(
SELECT 1 FROM dbo.Token t1
WHERE t.id = t1.id
AND t1.status = 'used'
)
OR
(
EXISTS(
SELECT 1 FROM dbo.Token t1
WHERE t.id = t1.id
AND t1.status = 'taken'
)
AND NOT EXISTS(
SELECT 1 FROM dbo.Token t1
WHERE t.id = t1.id
AND t1.status = 'deleted'
)
)
Demo
Use aggregation and a having clause to get the list of eligible ids:
SELECT id
FROM token t
GROUP BY id
HAVING SUM(case when status = 'taken' then 1 else 0 end) > 0 or
SUM(case when status = 'used' then 1 else 0 end) > 0;
To get the count, use a subquery or CTE:
SELECT COUNT(*)
FROM (SELECT id
FROM token t
GROUP BY id
HAVING SUM(case when status = 'taken' then 1 else 0 end) > 0 or
SUM(case when status = 'used' then 1 else 0 end) > 0
) t
Try this:
SELECT SUM(CASE WHEN (CHARINDEX('used', data.status) > 0) OR (data.status = 'taken') THEN 1 ELSE 0 END) as [count]
FROM
(
SELECT DISTINCT id, (SELECT STUFF((SELECT Distinct ',' + status
FROM token a
WHERE a.id = b.id
FOR XML PATH (''))
, 1, 1, '')) as status
FROM token b
) data
Demo
You need to be able to take into account all three conditions, so a naive approach would be to just compare each three with a case statement:
WITH grouped as
(
select id from #uses group by id
)
select grouped.id,
used =
CASE WHEN used.id is not null THEN 'YES'
WHEN taken.id is not null and deleted.id is null THEN 'YES'
ELSE 'NO'
END
from grouped
left join #uses taken on grouped.id = taken.id
and taken.use_status = 'taken'
left join #uses used on grouped.id = used.id
and used.use_status = 'used'
left join #uses deleted on grouped.id = deleted.id
and deleted.use_status = 'deleted'
The case statement will stop whenever the condition is met, so you only need to WHEN's and an ELSE to meet the conditions.
This is a naive approach, though, and assumes that you only ever have one row per id and use status type. You'd have to do some additional work if that wasn't the case.
if token has been taken and used -> do not count it
SELECT
SUM(DECODE(status, 'taken', 1, 0)) +
SUM(DECODE(status, 'used', 1, 0)) -
SUM(DECODE(status, 'deleted', 1, 0))
FROM
token t
WHERE
status <> 'used' OR
EXISTS(SELECT 1 FROM token t2 WHERE t2.id = t.id and t2.status = 'deleted')
if token has been taken and used -> count it
SELECT
COUNT(1)
FROM
token t
WHERE
status = 'taken' AND
(
EXISTS(SELECT 1 FROM token t2 WHERE t2.id = t.id and t2.status = 'used') OR
NOT EXISTS(SELECT 1 FROM token t2 WHERE t2.id = t.id and t2.status = 'deleted')
)
Coming back to this question, one solution could be with using Pivot
SELECT COUNT(id)
FROM (
SELECT id, status FROM Token
) src
PIVOT
(
COUNT(status) FOR status IN ([taken], [used], [deleted])
) pvt
WHERE (taken = 1 AND deleted = 0)OR (used = 1)
DEMO

counting records on the same table with different values possibly none sql server 2008

I have a inventory table with a condition i.e. new, used, other, and i am query a small set of this data, and there is a possibility that all the record set contains only 1 or all the conditions. I tried using a case statement, but if one of the conditions isn't found nothing for that condition returned, and I need it to return 0
This is what I've tried so far:
select(
case
when new_used = 'N' then 'new'
when new_used = 'U' then 'used'
when new_used = 'O' then 'other'
end
)as conditions,
count(*) as count
from myDB
where something = something
group by(
case
when New_Used = 'N' then 'new'
when New_Used = 'U' then 'used'
when New_Used = 'O' then 'other'
end
)
This returns the data like:
conditions | count
------------------
new 10
used 45
I am trying to get the data to return like the following:
conditions | count
------------------
new | 10
used | 45
other | 0
Thanks in advance
;WITH constants(letter,word) AS
(
SELECT l,w FROM (VALUES('N','new'),('U','used'),('O','other')) AS x(l,w)
)
SELECT
conditions = c.word,
[count] = COUNT(x.new_used)
FROM constants AS c
LEFT OUTER JOIN dbo.myDB AS x
ON c.letter = x.new_used
AND something = something
GROUP BY c.word;
try this -
DECLARE #t TABLE (new_used CHAR(1))
INSERT INTO #t (new_used)
SELECT t = 'N'
UNION ALL
SELECT 'N'
UNION ALL
SELECT 'U'
SELECT conditions, ISNULL(r.cnt, 0) AS [count]
FROM (
VALUES('U', 'used'), ('N', 'new'), ('O', 'other')
) t(c, conditions)
LEFT JOIN (
SELECT new_used, COUNT(1) AS cnt
FROM #t
--WHERE something = something
GROUP BY new_used
) r ON r.new_used = t.c
in output -
new 2
used 1
other 0
You can do it as a cross-tab:
select
sum(case when new_used = 'N' then 1 else 0 end) as N,
sum(case when new_used = 'U' then 1 else 0 end) as U,
sum(case when new_used = 'O' then 1 else 0 end) as Other
from myDB
where something = something