exists/not exists without referring to outer table - sql

I am working on Activiti framework. This is a workflow automation framework in java. I have following query:
select RES.* from ACT_RU_TASK RES where exists
(select 1 from ACT_RU_IDENTITYLINK I where not exists
(
select 1 from ACT_RU_VARIABLE A0 where RES.ID_ = A0.TASK_ID_ and A0.NAME_= 'excludedUserForTask'
and A0.TYPE_ = 'string' and A0.TEXT_ ='my_id'
)
and I.TASK_ID_ = RES.ID_ and I.TYPE_ = 'candidate' and I.GROUP_ID_ IN ('my_skill_1')
)
and
RES.ASSIGNEE_ is null order by RES.priority_ desc ,RES.create_time_ LIMIT 10 OFFSET 0;
So, my objective is to fetch all the tasks(from table ACT_RU_TASK) which are not yet assigned(RES.ASSIGNEE_ is null), and which are not assignable to this user('my_id'), and need skill 'my_skill_1'. In activiti,ACT_RU_IDENTITYLINK table contains the link between a task and a skill(GROUP_ID_), and ACT_RU_VARIABLE contains information on variables associated to a task(here we ensure that variable 'excludedUserForTask' and 'my_id' are not paired).
But problem I face is that apart from tasks which need skill 'my_skill_1', I get other tasks too which need other skills.
Looking at the query, I am not sure about this part:
select 1 from ACT_RU_IDENTITYLINK I where not exists
(
select 1 from ACT_RU_VARIABLE A0 where RES.ID_ = A0.TASK_ID_ and A0.NAME_= 'excludedUserForTask'
and A0.TYPE_ = 'string' and A0.TEXT_ ='my_id'
)
and I.TASK_ID_ = RES.ID_ and I.TYPE_ = 'candidate' and I.GROUP_ID_ IN ('my_skill_1')
In subquery for NOT EXISTS, we are not referring to ACT_RU_IDENTITYLINK. Does exist/not exist work this way? I think we need to refer outer table(ACT_RU_IDENTITYLINK) too in subquery.

I believe that the not exists part has to be part of the outer query condition like this
select RES.*
from ACT_RU_TASK RES
where exists
(
select 1
from ACT_RU_IDENTITYLINK I
and I.TASK_ID_ = RES.ID_
and I.TYPE_ = 'candidate'
and I.GROUP_ID_ IN ('my_skill_1')
)
and not exists
(
select 1
from ACT_RU_VARIABLE A0
where RES.ID_ = A0.TASK_ID_
and A0.NAME_= 'excludedUserForTask'
and A0.TYPE_ = 'string' and A0.TEXT_ ='my_id'
)
and RES.ASSIGNEE_ is null
order by RES.priority_ desc ,RES.create_time_
LIMIT 10 OFFSET 0;

Related

Add an alias for a subquery that I can reference in the main WHERE clause

I want to create an alias for a subquery so I can reference in the WHERE clause from the main query but it keeps throwing me error telling me that the column doesn't exist.
SELECT x.id_lib, (
SELECT sg.nom FROM subgenres sg WHERE (x.id_gen = sg.id)
)as genname, x.id_gen
FROM subgenres_books x WHERE x.id_lib = 1 and genname LIKE 'Satira'
As zip suggests, you can phrase the query as a simple join:
SELECT sb.id_lib, s.nom, sb.id_gen
FROM subgenres_books sb JOIN
subgenres s
ON s.id_gen = sb.id
WHERE sb.id_lib = 1 and s.nom = 'Satira';
However, there seems to be no reason to return the subgenre -- it is constant. So I'm thinking that an EXISTS subquery is appropriate:
SELECT sb.id_lib, sb.id_gen
FROM subgenres_books sb
WHERE sb.id_lib = 1 AND
EXISTS (SELECT 1
FROM subgenres s
WHERE s.id_gen = sb.id
s.nom = 'Satira'
);
Try this:
SELECT x.id_lib, x.id_gen, genname.nom
FROM subgenres_books x inner join
subgenres genname on x.id_gen = genname.id
WHERE x.id_lib = 1 and genname.nom LIKE 'Satira'

How to Get a Count of Records Using Partitioning in Oracle

I have the following query:
SELECT
F.IID,
F.E_NUM AS M_E_NUM,
MCI.E_NUM AS MCI_E_NUM,
F.C_NUM AS M_C_NUM,
MCI.C_NUM AS MCI_C_NUM,
F.ET_ID AS M_ET_ID,
EDIE.ET_ID AS ED_INDV_ET_ID,
COUNT(*) OVER (PARTITION BY F.IID) IID_COUNT
FROM FT_T F JOIN CEMEI_T MCI ON F.IID = MCI.IID
JOIN EDE_T EDE ON MCI.E_NUM = EDE.E_NUM
JOIN EDIE_T EDIE ON EDIE.IID = F.IID AND EDIE.ET_ID = EDE.ET_ID
WHERE
F.DEL_F = 'N'
AND MCI.EFF_END_DT IS NULL
AND MCI.TOS = 'BVVB'
AND EDE.PTEND_DT IS NULL
AND EDE.DEL_S = 'N'
AND EDE.CUR_IND = 'A'
AND EDIE.TAR_N = 'Y'
AND F.IID IN
(
SELECT DISTINCT IID
FROM FT_T
WHERE GROUP_ID = 'BG'
AND DEL_F = 'N'
AND (IID, E_NUM) NOT IN
(
SELECT IID, E_NUM FROM CEMEI_T
WHERE TOS = 'BVVB' AND EFF_END_DT IS NULL
)
);
I am basically grabbing information from several tables and creating a flat record of them.
Everything works accordingly except now I need to find out whether there are two records in FT_T table with identical IID's and display that count as part of the result set.
I tried to use partitioning but all the rows in the result set return a single count even though there are ones that have 2 records with identical IID's in FT_T.
The reason I initially said that I'm gathering information from several tables is due to the fact that FT_T might not have all the information I need if two records are not available for the same IID, so I have to retrieve them from other tables JOINed in the query. However, I need to know which FT_T.IID's have two records in FT_T (or greater than one).
Perhaps you need to calculate the count before the join and filtering:
SELECT . . .
FROM (SELECT F.*,
COUNT(*) OVER (PARTITION BY F.IID) as IID_CNT
FROM FT_T F
) JOIN
CEMEI_T MCI
ON F.IID = MCI.IID JOIN
EDE_T EDE
ON MCI.E_NUM = EDE.E_NUM JOIN
EDIE_T EDIE
ON EDIE.IID = F.IID AND EDIE.ET_ID = EDE.ET_ID
. . .
this is merely a comment/observation, but formatting is needed
You use of in(...) with select distinct and not in(...,...) seems complex and could be a problem if some values are NULL. I suggest you consider using EXISTS and NOT EXISTS instead. e.g.
AND EXISTS (
SELECT
NULL
FROM FT_T
WHERE F.IID = FT_T.IID
AND FT_T.GROUP_ID = 'BG'
AND FT_T.DEL_F = 'N'
AND NOT EXISTS (
SELECT
NULL
FROM CEMEI_T
WHERE FT_T.IID = CEMEI_T.IID
AND FT_T.E_NUM = CEMEI_T.E_NUM
AND CEMEI_T.TOS = 'BVVB'
AND CEMEI_T.EFF_END_DT IS NULL
)
)

WHERE Clause does not accept just defined column

This Code does not work:
SELECT
(
SELECT [T_Licence].[isInstalled]
FROM [T_Licence]
WHERE [T_Licence].[System] = [T_System].[ID]
AND [T_Licence].[Software] = 750
) AS [IsInstalled] ,*
FROM [T_System]
WHERE [IsInstalled] = 1
I have to do it this way, but this makes the whole code so complicated. I really dont want that:
SELECT
(
SELECT [T_Licence].[isInstalled]
FROM [wf_subj_all].[T_Licence]
WHERE [T_Licence].[System] = [T_System].[ID]
AND [T_Licence].[Software] = 750
) AS [IsInstalled] ,*
FROM [wf_subj_it].[T_System]
WHERE
(
SELECT
(
SELECT [T_Licence].[isInstalled]
FROM [wf_subj_all].[T_Licence]
WHERE [T_Licence].[System] = [T_System].[ID]
AND [T_Licence].[Software] = 750
)
) = 1
Is there any way to do it like shown in the first code snippet?
So that the code stays somehow readeble.
thx very much
Try this one -
SELECT *
FROM wf_subj_it.T_System s
CROSS APPLY (
SELECT /*TOP(1)*/ t.isInstalled
FROM wf_subj_all.T_Licence t
WHERE t.[System] = s.ID
AND t.Software = 750
) t
WHERE t.isInstalled = 1
Just wrap the query with an outer select and it should work.
SELECT *
FROM
(
SELECT
(
SELECT [T_Licence].[isInstalled]
FROM [T_Licence]
WHERE [T_Licence].[System] = [T_System].[ID]
AND [T_Licence].[Software] = 750
) AS [IsInstalled], *
FROM [T_System]
) As tbl1
WHERE [IsInstalled] = 1
The assumptions I made for my answer:
You're trying to select the systems (table T_System) which have software with id=750 installed
The table T_License contains the installed information
There is a 1:n relation between T_System and T_License: T_License may contain 0, 1 or more records per Sytem value...
but the combination System plus Software is unique
I think this will work
SELECT l.[isInstalled], s.*
FROM [wf_subj_it].[T_System] AS s
INNER JOIN [wf_subj_it].[T_License] AS l
ON l.[System] = s.[ID]
AND l.[Software] = 750
AND l.isInstalled = 1

Deleting rows from a SQL table based on specific criteria

I have a table that contains the following fields: issues to go (itg), customer number (ctm_nbr) and pub code (pub_cde). The data looks like this
12 010000024412 CTR
6 010000024412 RTF
18 010000002325 CTR
9 010000002325 RTF
3 010000014789 CTR
1 010000014789 RTF
I need to be able to delete all of the records where the RTF pub code and matching customer number is half of the issues to go (itg) in the CTR pub code for that matching customer. That way once I have all the records removed I would only have records like this remaining:
3 010000014789 CTR
1 010000014789 RTF
You might use something like: Delete all records for customer number x where the customer number has issues to go in CTR field that are twice the issues to go in the RTF field.
Delete
from --table--
where ctm_nbr in (select t2.ctm_nbr
from --table-- t2 join --table-- t3
ON (t2.ctm_nbr = t3.ctm_nbr)
where t2.pub_cde="CTR"
and t3.pub_cde="RTF"
and t2.itg = 2*t3.itg
)
The tricky bit is getting both related records at one time:
delete
a1
from
a a1
where (
a1.pub_cde = 'RTF' and
exists (
select 'x'
from a a2
where a2.ctm_nbr = a1.ctm_nbr and
a2.pub_cde = 'CTR' and
a2.itg = 2 * a1.itg
)
) or (
a1.pub_cde = 'CTR' and
exists (
select 'x'
from a a2
where a2.ctm_nbr = a1.ctm_nbr and
a2.pub_cde = 'RTF' and
a2.itg * 2 = a1.itg
)
);
Example SQL Fiddle
You can use conditional aggregation:
delete from tbl
where ctm_nbr in(
select ctm_nbr
from tbl
group by ctm_nbr
having max(case when pub_cde = 'CTR' then cast(itg as decimal) end) /
max(case when pub_cde = 'RTF' then cast(itg as decimal) end) = 2)
Fiddle: http://sqlfiddle.com/#!6/a7efe/1/0
The reason I casted itg as decimal is to avoid the rounding issue that would otherwise occur due to your column being an interger data type (thanks to Laurence for pointing that out).
DELETE t1
FROM a t1
INNER JOIN a t2
ON t1.ctm_nbr = t2.ctm_nbr
WHERE
((t1.pub_cde = 'CTR') AND
(t2.pub_cde = 'RTF') AND
(2*t2.itg = t1.itg))
OR
((t2.pub_cde = 'CTR') AND
(t1.pub_cde = 'RTF') AND
(2*t1.itg = t2.itg))

All rows where at least one child has all of its own children pass a condition

I'm having a little trouble with a SQL query, and thought I'd solicit the wisdom of the crowd to see what I'm missing. I'm pretty sure the below works, but it seems really poor and I'm wondering if there's a smarter way (ideally using joins instead of sub-selects) to do this.
The Problem
Let's say I have some tables:
Prize
- PrizeId
RulePrize_Map
- PrizeId
- RuleId
Rule
- RuleId
Conditional
- ConditionalId
- RuleId
- InputId
- ExpectedValue (bit)
Input
- InputId
A Prize is won when at least one Rule is true. A Rule is true when all of its Conditionals are true. A Conditional is "true" when its InputId is either present or not present in the Input table, as designated by the ExpectedValue field. This could perhaps be treated as equivalent to: Count(InputId in Input table) = ExpectedValue for the Conditional's InputId.
Some Examples:
Conditional (InputId = 11, ExpectedValue = 1) -> True if InputId 11 in Input Table
Conditional (InputId = 12, ExpectedValue = 0) -> True if Inputid 12 NOT in Input Table
My Goal
I want to get all Prizes where at least one Rule is "true". I would settle for: "All Rules that are true".
My Attempt
select p.PrizeId from Prize p INNER JOIN RulePrize_Map rpm ON rpm.PrizeId = p.PrizeId
WHERE p.PrizeId IN
(select r.PrizeId from Rule r
where
(select count(*) from Conditional c1 where c1.RuleId = r.RuleId)
=
(select count(*) from Conditional c2
where c2.RuleId = r.RuleId AND
(select count(*) from Input i where i.InputId = c2.InputId) = c2.ExpectedValue
)
)
GROUP BY p.prizeId
The question change a bit, so I have redone the answer...
SELECT
PrizeId
FROM
(
SELECT
PrizeRule_Map.PrizeId,
PrizeRule_Map.RuleId
FROM
PrizeRule_Map
INNER JOIN
Rule
ON Rule.RuleId = PrizeRule_Map.RuleId
INNER JOIN
Conditional
ON Conditional.RuleId = Rule.RuleID
LEFT JOIN
Input
ON Input.InputId = Conditional.InputID
GROUP BY
PrizeRule_Map.PrizeId,
PrizeRule_Map.RuleId
HAVING
COUNT(*) = SUM(CASE Conditional.ExpectedValue
WHEN 1 THEN CASE WHEN Input.InputId IS NULL THEN 0 ELSE 1 END
WHEN 0 THEN CASE WHEN Input.InputId IS NULL THEN 1 ELSE 0 END
END
)
)
AS map
GROUP BY
PrizeId
To get all RuleIds where ALL Conditionals are true:
SELECT r.RuleID
FROM Rule r
JOIN Conditional c
ON c.RuleId = r.RuleId
LEFT JOIN Input i
ON i.InputId = c.InputId
GROUP BY r.RuleID
HAVING COUNT( CASE WHEN (c.ExpectedValue=1) AND (i.InputId IS NOT NULL)
OR (c.ExpectedValue=0) AND (i.InputId IS NULL)
THEN 1
ELSE NULL
END )
= COUNT( * )
Another way - probably slower but it doesn't hurt to test for speed. It doesn't use CASE but the difference (EXCEPT) of two JOINs, only one of them using GROUP BY:
SELECT r.RuleID
FROM Rule r
JOIN Conditional c
ON c.RuleId = r.RuleId
LEFT JOIN Input i
ON i.InputId = c.InputId
WHERE c.ExpectedValue = 1
GROUP BY r.RuleID
HAVING COUNT( i.InputId ) = COUNT( * )
EXCEPT
SELECT r.RuleID
FROM Rule r
JOIN Conditional c
ON c.RuleId = r.RuleId
JOIN Input i
ON i.InputId = c.InputId
WHERE c.ExpectedValue = 0
Try the following:
SELECT Rule.RuleId, Rule.RuleName
FROM Rule
INNER JOIN Conditional ON Rule.RuleId = Conditional.RuleId
Where Conditional.ExpectedValue == true