I've been scratching my head about this.
I have a table with multiple columns for the same project.
However, each project can have multiple rows of a different type.
I would like to find only projects type O and only if they don't have other types associated with them.
Ex:
Project_Num | Type
1 | O
1 | P
2 | O
3 | P
In the case above, only project 2 should be returned.
Is there a query or a method to filter this information? Any suggestions are welcome.
If I understand correctly, you want to check that the project has only record for its project number and it has type 'O'. You can use below query to implement this:
;with cte_proj as
(
select Project_Num from YourTable
group by Project_Num
having count(Project_Num) = 1)
select Project_Num from cte_proj c
inner join YourTable t on c.Project_Num = t.Project_Num
where t.Type = 'O'
You can do this using not exists:
select p.*
from projects p
where type = 'O' and
not exists (select 1
from projects p2
where p2.project_num = p.project_num and p2.type <> 'O'
);
You can also do this using aggregation:
select p.project_num
from projects p
group by p.project_num
having sum(case when p.type = 'O' then 1 else 0 end) > 0 and
sum(case when p.type <> 'O' then 1 else 0 end) = 0;
Another option (pretty fast)
SELECT p0.*
FROM project p0
LEFT JOIN project p1 ON (p0.Type<>p1.Type AND p0.Project_Num=p1.Project_Num)
WHERE p0.Type='O' AND p1.Type IS NULL;
Related
I have a classification table that looks like this:
ID CLASSIFICATION
__________________
A1 BOARD
A2 SURFBOARD
A3 SURF
Then I have a category table that looks like this
CATEGORY PARENT INDENT
____________________________________
SURF NULL 3
SURFBOARD SURF 2
BOARD SURFBOARD 1
I want to make a SQL query, that returns this:
INDENT3 INDENT2 INDENT1 ID
______________________________________
SURF NULL NULL A3
SURF SURFBOARD NULL A2
SURF SURFBOARD BOARD A1
Is it possible?. I'm not getting any ideas, seems like I need to loop through the classification table and find if there is indent1, indent2 and indent3. But not sure If I can put a script in a query, or if there is some kind of query I can do to achieve this. Something like
FOREACH CLASSIFICATION
CASE EXIST CATEGORY WITH IDENT1 INDENT 1 ELSE NULL AS IDENT1,
CASE EXIST CATEGORY WITH IDENT2 INDENT 2 ELSE NULL AS IDENT2,
CASE EXIST CATEGORY WITH IDENT1 INDENT 3 ELSE NULL AS IDENT3
If your hierarchy has a maximum of 3 levels a simpler query may be:
select cl.classification as indent3, null as indent2, null as indent1, id
from classification cl
join category ca on ca.category = cl.classification
where ca.indent = 3
union
select ca2.category, cl.classification, null as indent3, id
from classification cl
join category ca on ca.category = cl.classification
join category ca2 on ca.parent = ca2.category
where ca.indent = 2
union
select ca3.category as indent3, ca2.category as indent2, cl.classification as indent1, id
from classification cl
join category ca on ca.category = cl.classification
join category ca2 on ca.parent = ca2.category
join category ca3 on ca2.parent = ca3.category
where ca.indent = 1
If you have an indefinite number of parent/child levels you might be better to search "parent hierarchy with CTE" for a more complicated but flexible method.
Your logic is a bit hard to follow, but this should product the results that you specify:
select max(case when cl.indent = 3 then cl.category end) over () as indent3,
(case when cl.indent < 3
then max(case when cl.indent = 2 and then cl.category end) over ()
end) as indent2,
(case when cl.indent < 2
then max(case when cl.indent = 1 and then cl.category end) over ()
end) as indent1,
cl.id
from category ca join
classification cl
on ca.category = cl.category
People not so god with SQL will tell you to avoid this, SQL gurus consider to treat you as one of the pack.
It somewhat hard to understand your model but I gave it a shot.
Bit tip from the coach, if you need an id, use incremental numbers from the database, it's faster, allow god index and no risk of unexpected duplicates or truncation.
CREATE TABLE cs (id char(10), classification char(20));
CREATE TABLE ct (category char(20), parent char(20), indent int);
INSERT INTO cs VALUES
('A1','BOARD'),
('A2','SURFBOARD'),
('A3','SURF');
INSERT INTO ct VALUES
('SURF',null,3),
('SURFBOARD','SURF',2),
('BOARD','SURFBOARD',1);
select cs.id, ct1.category indent1,ct2.category indent2,ct3.category indent3 from ct ct1
left join ct ct2 on ct2.category = ct1.parent
left join ct ct3 on ct3.category = ct2.parent
left join cs on cs.classification = ct1.category
Link to the code on SQLFiddle
I have two very similar sql statements
select instrumentuniqueid, count(levelid) as errors
from dbo.testevent
join dbo.test
on dbo.test.id = dbo.testevent.testid where dbo.test.runid = 20962 and dbo.testevent.levelid = 1
group by instrumentuniqueid
select instrumentuniqueid, count(levelid) as warnings
from dbo.testevent
join dbo.test
on dbo.test.id = dbo.testevent.testid where runid = 20962 and levelid = 2
group by instrumentuniqueid
The first one produces columns of instrumentuniqueid (aggregated) and the count
The second one produces columns of aggregated instrumentuniqueid with a different count.
How can I join them together so that the final table looks like:
Instrumentuniqueid | Errors | Warnings
Use conditional aggregation:
select instrumentuniqueid,
sum(case when te.levelid = 1 then 1 else 0 end) as errors,
sum(case when te.levelid = 2 then 1 else 0 end) as warnings
from dbo.testevent te join
dbo.test t
on t.id = t2.testid
where t.runid = 20962
group by instrumentuniqueid;
Table aliases also make a query easier to write and to read.
In Oracle how do I find Cars which must have Feature1 and have at lest, one out of Feature2 or Feature3. Sample table and expected result should look like below screenshot. Thanks Kiran
This should work:
select t1.car, t1.feature
from yourtable t1
inner join
( -- inner select returns the cars with the Feature1 and Feature2 or Feature3
select car, feature
from yourtable
where feature = 'Feature1'
and exists (select car
from yourtable
where feature in ('Feature2', 'Feature3'))
) t2
on t1.car = t2.car
where t1.feature in ('Feature1', 'Feature2', 'Feature3') -- this excludes any other features
see SQL Fiddle with Demo
I like to do this with GROUP BY and HAVING:
select car
from t
group by car
having max(case when feature = 'Feature1' then 1 else 0 end) = 1 and
max(case when feature in ('Feature1', 'Feature2') then 1 else 0 end) = 1
This query returns the cars. To get the featuers as well, you have to join tis back in:
select t.*
from (select car
from t
group by car
having max(case when feature = 'Feature1' then 1 else 0 end) = 1 and
max(case when feature in ('Feature1', 'Feature2') then 1 else 0 end) = 1
) c join
t
on t.car = c.car
I like this method, because the same idea can be used for handling many different similar queries -- AND conditions, OR conditions, different subgroups, and different counts.
I have a 2 tables:
Questions table with Question ID
Part Table:
Question ID
Part ID
BAllPartsRequired
The user will select some parts (or may select none) and depending on what was selected certain questions will be displayed.
I want to join the 2 tables for 3 scenerios but do them all in 1 query. I can write each scenerio individually (EDIT I thought I could but scenario 3 I can not get to work where it requires all found in part table to be selected) but can not figure out how to get them all in 1 query (I have done something similar before but cant remember how).
If no parts exist in part table for that question retruen the question
If any part selected exists in part table return question (i.e. user selects 1 part and 5 parts are associated to that question then the question will match and be returned). BAllPartsRequired = false
If user selects parts and ALL of the parts are associated to the question the question is returend but if NOT all parts are selected by user the question is not returend (i.e. user selects 3 parts and there are 4 parts in table then the user will not see the question, but if the user selectes all 4 parts the question will be shown). BAllPartsRequired = true
I am an advanced SQL programmer but this is eluding me and I know I have done this before but how do I get it to work in 1 query, do I do a nested join, a left join, a case on the where statement or something else.
Sample Data:
Question Form Association:
NFormAssociationID NQuestionID FormType
1 1 PAEdit
2 2 PAEdit
3 3 PAEdit
4 4 PAEdit
Question Part Form Association Table:
ID NFormAssociationID PartNumber BAllPartsRequired
1 1 1 0
2 2 2 1
3 2 3 1
Query without the new parts table added:
Select ROW_NUMBER() OVER(ORDER BY QL.NOrderBy) AS RowNumber,
QL.NQuestionID, QL.FieldName, QL.Question, QL.BRequired, QFL.FormFieldType, QFL.SingleMultipleSM,
QFL.CSSStyle
FROM dbo.QuestionFormAssociation QA WITH (NOLOCK)
INNER JOIN dbo.QuestionLookup QL WITH (NOLOCK) ON QA.NQuestionID = QL.NQuestionID
INNER JOIN dbo.QuestionFieldTypeLookup QFL WITH (NOLOCK) ON QL.NFieldTypeID = QFL.NFieldTypeID
WHERE QA.BActive = 1 AND QL.BActive = 1 AND QFL.BActive=1
AND QA.FormType = 'PAEdit'
ORDER BY QL.NOrderBy
Simple query using new table
Select ID
FROM dbo.QuestionPartFormAssociation
WHERE BAllPartsRequired = 1
AND PartNumber IN ('1', '2') --'1', '2', '3')
It sounds like you are trying to find the eligible questions, based on some criteria.
In this sitatuion, it is best to summarize first at the question level, and then apply logic to those summaries. Here is an example:
select q.questionid
from (select q.questionid,
max(case when qp.questionid is null then 1 else 0 end) as HasNoParts,
sum(case when qp.partid in (<user parts>) then 1 else 0 end) as NumUserParts,
count(qp.questionid) as NumParts,
max(qp.AllPartsRequired) as AreAllPartsRequired
from question q left outer join
questionpart qp
on q.questionid = qp.questionid
group by q.questionid
) q
where HasNoParts = 1 or -- condition 1
AreAllPartsRequired = 0 and NumUserParts > 0 or -- condition 2
AreAllPartsRequired = 1 and NmUserParts = NumParts -- condition 3
I've simplified the table and column names to make the logic clearer.
updated with full answer from OP:
Select ROW_NUMBER() OVER(ORDER BY QL.NOrderBy) AS RowNumber,
QL.NQuestionID, QL.FieldName, QL.Question, QL.BRequired, QFL.FormFieldType, QFL.SingleMultipleSM,
QFL.CSSStyle
FROM dbo.QuestionFormAssociation QA WITH (NOLOCK)
INNER JOIN dbo.QuestionLookup QL WITH (NOLOCK) ON QA.NQuestionID = QL.NQuestionID
INNER JOIN dbo.QuestionFieldTypeLookup QFL WITH (NOLOCK) ON QL.NFieldTypeID = QFL.NFieldTypeID
INNER JOIN (
select q.NFormAssociationID,
max(case when qp.NFormAssociationID is null then 1 else 0 end) as HasNoParts,
sum(case when qp.PartNumber in ('1','2','3') then 1 else 0 end) as NumUserParts,
count(qp.NFormAssociationID) as NumParts,
qp.BAllPartsRequired
from QuestionFormAssociation q
left outer join QuestionPartFormAssociation qp on q.NFormAssociationID = qp.NFormAssociationID
AND QP.BActive = 1
WHERE Q.FormType = 'PAEdit'
AND Q.BActive = 1
group by q.NFormAssociationID, qp.BAllPartsRequired
) QSUB ON QA.NFormAssociationID = QSUB.NFormAssociationID
WHERE QA.BActive = 1 AND QL.BActive = 1 AND QFL.BActive=1
AND (
QSUB.HasNoParts = 1 -- condition 1
OR (QSUB.BAllPartsRequired = 0 and QSUB.NumUserParts > 0) -- condition 2
OR (QSUB.BAllPartsRequired = 1 and QSUB.NumUserParts = QSUB.NumParts) -- condition 3
)
ORDER BY QL.NOrderBy
I am newbie to SQL Joins.
I have two tables
Version
Vid, VName, IsActive
1 V1 1
2 V2 0
3 V3 1
Sub-Version
SVid,Vid, VName
1 1 0.1
2 1 0.2
3 2 0.1
In above tables each Version has many Sub-Version's .
I need to fetch results from the above tables where the output should be like this.
Vid, VName, IsActive, SubVersionExists(Bit)
1 V1 1 1
2 V2 0 1
3 V3 1 0
in above result set the column name "SubVersionExists" represents if the version has SubVersion records in Sub-Version table.
Hope this explains the problem scenario well.
Thanks in advance.
Here is a version without joins, but using EXISTS (SELECT ... ) which returns a boolean value:
http://sqlfiddle.com/#!5/712bd/9
SELECT
Version.Vid, Version.VName, Version.IsActive,
EXISTS (
SELECT NULL FROM SubVersion WHERE SubVersion.Vid = Version.Vid
) AS SubVersionExists
FROM Version;
Or, if your sql engine doesn't convert booleans to 0/1, you can use CASE:
SELECT
Version.Vid, Version.VName, Version.IsActive,
CASE WHEN
EXISTS (SELECT NULL FROM SubVersion WHERE SubVersion.Vid = Version.Vid)
THEN 1 ELSE 0 END AS SubVersionExists
FROM Version
Another version with LEFT JOIN + GROUP BY, if you don't want to use COUNT():
SELECT
Version.Vid, Version.VName, Version.IsActive,
CASE WHEN SubVersionVids.Vid IS NOT NULL
THEN 1 ELSE 0 END AS SubVersionExists
FROM Version
LEFT JOIN (
SELECT SubVersion.Vid
FROM SubVersion
GROUP BY SubVersion.Vid
) AS SubVersionVids
ON SubVersionVids.Vid = Version.Vid;
Or you can use DISTINCT instead of GROUP BY:
SELECT
Version.Vid, Version.VName, Version.IsActive,
CASE WHEN SubVersionVids.Vid IS NOT NULL
THEN 1 ELSE 0 END AS SubVersionExists
FROM Version
LEFT JOIN (
SELECT DISTINCT SubVersion.Vid
FROM SubVersion
) AS SubVersionVids
ON SubVersionVids.Vid = Version.Vid;
select v.vid,v.vname,v.isactive,count(s.svid) as SubVersionExists from
Version v left join Sub-Version s on v.vid=s.vid group by v.vid;
Here SubVersionExists's value will be greater than zero if sub version exists for respective version.
select v.vid,v.vname,v.isactive, case when count(s.svid) > 0 then 1 else 0 end
as SubVersionExists from Version v left join Sub-Version s on v.vid=s.vid
group by v.vid;
This query will give the desired result i.e. SubVersionExists's value will be 1 if sub version exists for respective version else zero.
SELECT V.VID, V.NAME, V.ISACTIVE,
CASE
WHEN COUNT(SV.SVID)=0 then '0'
WHEN COUNT(SV.SVID)>0 then '1'
END
VERSION V LEFT JOIN SUBVERSION SV ON V.VID=SV.VID
GROUP BY V.VID, V.NAME, V.ISACTIVE
Hey I have also found a solution for this question with CASE and IS NOT NULL and DISTICT with a left outer join
Solution:
SELECT DISTINCT v.vid,v.vname,v.isactive,
'SubVersionExists' = CASE WHEN vs.vid IS NOT NULL THEN 1 ELSE 0 END
FROM VERSION v
LEFT OUTER JOIN
subversion vs
ON v.vid = vs.vid