SQL Query - SQL Developer - sql

I have a problem with the below query. Basically the query below gives me all items from a ITEM_MASTER table, that are located at location '9999' from the ITEM_LOCATION table and that have a status of 'C' again in the ITEM_LOCATION table. I want to check if any of these items in the query below are also at any other location and have a status of 'A'.
So basically I want too cross reference the items from this query, to see if any of them also appear at any other location, not just 9999 and if they have a status of 'A'
SELECT IM.ITEM MIN,
IM.ITEM_DESC,
IL.ITEM MIN,
IL.LOC,
IL.STATUS
FROM ITEM_MASTER IM,ITEM_LOC IL
WHERE IM.ITEM_LEVEL = 2
AND IM.TRAN_LEVEL = 2
AND IL.STATUS = 'C'
AND IM.ITEM = IL.ITEM
AND IL.LOC = 9999;
Thanks!

First, you should write your query using proper join syntax:
SELECT IM.ITEM MIN, IM.ITEM_DESC,
IL.ITEM MIN, IL.LOC, IL.STATUS
FROM ITEM_MASTER IM JOIN
ITEM_LOC IL
ON IM.ITEM = IL.ITEM
WHERE IM.ITEM_LEVEL = 2 AND IM.TRAN_LEVEL = 2 AND IL.STATUS = 'C' AND
IL.LOC = 9999;
You can accomplish what you want with exists:
SELECT IM.ITEM MIN, IM.ITEM_DESC,
IL.ITEM MIN, IL.LOC, IL.STATUS
FROM ITEM_MASTER IM JOIN
ITEM_LOC IL
ON IM.ITEM = IL.ITEM
WHERE IM.ITEM_LEVEL = 2 AND IM.TRAN_LEVEL = 2 AND IL.STATUS = 'C' AND
IL.LOC = 9999 AND
EXISTS (SELECT 1
FROM ITEM_MASTER IM2 JOIN
ITEM_LOC IL2
ON IM2.ITEM = IL2.ITEM
WHERE IM2.ITEM = IM.ITEM AND
IL2.LOC <> 9999 AND
IL2.STATUS = 'A'
);

Related

SQL : Percentage Completed

I need to have a SQL query to calculate the percentage of courses completed by location which are different SQL tables.
Courses table has a Status = 'C' (Completed status).
select Locations.Name, ( ??? ) as PercentCompleted
from Locations inner join Candidates ON Locations.Id = Candidates.SpecifiedLocation
inner join Courses on Candidates.Id = Courses.CandidateId
Group By Locations.Name
I want the results to be:
Location PercentCompleted
Loc1 10
Loc2 50
Loc3 75
where 10, 50 and 75 are percentages of courses completed per location.
Can this be achieved with a single SQL query?
If I understand correctly, I think you can do:
select l.Name,
avg(case when co.status = 'C' then 100.0 else 0 end) as PercentCompleted
from Locations l inner join
Candidates c
on l.Id = c.SpecifiedLocation inner join
Courses co
on c.Id = co.CandidateId
group by l.name;
try like below
select Locations.Name, (sum(case when Status = 'C' then 1 else 0 end)/(select count(*)
from Candidates c where c.SpecifiedLocation=Locations.Id))*100
as PercentCompleted
from Locations inner join Candidates ON Locations.Id = Candidates.SpecifiedLocation
inner join Courses on Candidates.Id = Courses.CandidateId
Group By Locations.Name

SQL sum and subtract issue with two queries

OK, I need somehelp. I have the following two queries:
SELECT DA.OWNG_OCD AS OFFICE, 'FL' AS STATE, SUM(S.STK_END_SEQ_NUM -
S.STK_STRT_SEQ_NUM) + COUNT(*) AS TOTSTK FROM STKRNG S, DFACCT DA, CMPNT C
WHERE RANGE_USED_SW = 'N' AND S.DFTACCT_CANUM = DA.DFTACCT_CANUM
AND DA.OWNG_OCD = C.OCD AND C.ST = 'FL' AND S.STK_TYP = 'R' GROUP
BY DA.OWNG_OCD;
AND
SELECT C.OCD, COUNT(*) AS USED FROM DRAFT D
JOIN STKRNG S ON S.DFTACCT_CANUM = D.DFTACCT_CANUM
JOIN DFACCT DA ON S.DFTACCT_CANUM = DA.DFTACCT_CANUM
JOIN CMPNT C ON CMPNT.OCD = DA.OWNG_OCD
WHERE D.DRFT_SEQ_NUM >= (SELECT MIN(S.STK_STRT_SEQ_NUM) FROM STKRNG S
WHERE D.DFTACCT_CANUM = S.DFTACCT_CANUM AND S.RANGE_USED_SW = 'N')
AND D.DRFT_SEQ_NUM <= (SELECT MAX(S.STK_END_SEQ_NUM) FROM STKRNG S WHERE
D.DFTACCT_CANUM = S.DFTACCT_CANUM AND S.RANGE_USED_SW = 'N')
AND S.STK_TYP = 'R'
AND S.RANGE_USED_SW = 'N'
AND C.ST = 'FL'
GROUP BY C.OCD;
I am trying to write one query where the results of the COUNT in the second query are subtracted from the results of the COUNT in the first query. Any idea on how to do this?
Put your queries in the from clause of your final query:
select q1.totstk - q2.used
from ( <your first query here> ) q1
join ( <your second query here> ) q2 on q2.ocd = q1.office;
try Something like this:
with STKRNGMINMAX as (
SELECT S.DFTACCT_CANUM,
MIN(S.STK_STRT_SEQ_NUM) MINNUM, MAX(S.STK_END_SEQ_NUM) MAXNUM,
SUM(S.STK_END_SEQ_NUM - S.STK_STRT_SEQ_NUM) DIFFNUM
FROM STKRNG S
WHERE (S.RANGE_USED_SW, S.STK_TYP)=('N', 'R')
group by S.DFTACCT_CANUM
)
SELECT C.OCD, S.DIFFNUM - COUNT(*) AS TOTSTK,
FROM DRAFT D
INNER JOIN STKRNGMINMAX S ON S.DFTACCT_CANUM = D.DFTACCT_CANUM and D.DRFT_SEQ_NUM between S.MINNUM AND S.MAXNUM
INNER JOIN DFACCT DA ON S.DFTACCT_CANUM = DA.DFTACCT_CANUM
INNER JOIN CMPNT C ON C.OCD = DA.OWNG_OCD and C.ST='FL'
GROUP BY C.OCD;

How to count the times a particular item appears in a query output

I have a query with a lot of tables and joins. So a simple Count(column) and Group By isn't working correctly.
The query returns an item list. I want to calculate how many times each item appears in that list.
Here's my query:
SELECT DECODE(BOM.ORGANIZATION_ID,203, 'CEC', 328, '3PL', 204, 'SIM') ORGANIZATION_CODE,
BOM.ORGANIZATION_ID,
MSI.SEGMENT1 "PARENT_ITEM",
MSIC.SEGMENT1 "COMPONENT_ITEM",
SUM(NVL(MMT.TRANSACTION_QUANTITY,0)) * NVL(SUM(CIC.ITEM_COST),0) "ANNUAL_MONEY",
SUM(NVL(MMT.TRANSACTION_QUANTITY,0)) "ANNUAL_QTY_USG",
NVL(SUM(CIC.ITEM_COST),0) "AVG_COST",
SUM(NVL(MSI.POSTPROCESSING_LEAD_TIME,0) + NVL(MSI.PREPROCESSING_LEAD_TIME,0)) LEAD_TIME
FROM BOM_BILL_OF_MATERIALS BOM
LEFT JOIN MTL_SYSTEM_ITEMS MSI
ON MSI.ORGANIZATION_ID = BOM.ORGANIZATION_ID
AND MSI.INVENTORY_ITEM_ID = BOM.ASSEMBLY_ITEM_ID
AND MSI.ENABLED_FLAG = 'Y'
AND MSI.BOM_ENABLED_FLAG = 'Y'
LEFT JOIN CST_ITEM_COSTS CIC
ON CIC.ORGANIZATION_ID = BOM.ORGANIZATION_ID
AND CIC.INVENTORY_ITEM_ID = BOM.ASSEMBLY_ITEM_ID
AND CIC.COST_TYPE_ID = 1
LEFT JOIN MTL_MATERIAL_TRANSACTIONS MMT
ON MMT.INVENTORY_ITEM_ID = BOM.ASSEMBLY_ITEM_ID
AND MMT.ORGANIZATION_ID = BOM.ORGANIZATION_ID
AND MMT.TRANSACTION_TYPE_ID IN (33,34,17)
LEFT JOIN MTL_TRANSACTION_TYPES MTT
ON MTT.TRANSACTION_TYPE_ID = MTT.TRANSACTION_TYPE_ID
LEFT JOIN BOM_INVENTORY_COMPONENTS BIC
ON BIC.BILL_SEQUENCE_ID = BOM.COMMON_BILL_SEQUENCE_ID
AND NVL(bic.disable_date, sysdate+1) > sysdate
LEFT JOIN BOM_COMPONENTS_B BCB
ON BIC.COMPONENT_SEQUENCE_ID = BCB.COMPONENT_SEQUENCE_ID
LEFT JOIN BOM_STRUCTURES_B BSB
ON BCB.BILL_SEQUENCE_ID = BSB.BILL_SEQUENCE_ID
LEFT JOIN MFG_LOOKUPS ML
ON ML.LOOKUP_CODE = BIC.WIP_SUPPLY_TYPE
AND ML.LOOKUP_CODE = BIC.ENFORCE_INT_REQUIREMENTS
AND ML.LOOKUP_TYPE = 'MTL_EAM_ITEM_TYPE'
LEFT JOIN MTL_SYSTEM_ITEMS MSIC
ON MSIC.ORGANIZATION_ID = BOM.ORGANIZATION_ID
AND MSIC.INVENTORY_ITEM_ID = BIC.COMPONENT_ITEM_ID
LEFT JOIN BOM_OPERATIONAL_ROUTINGS BOR
ON BOR.ASSEMBLY_ITEM_ID = BOM.ASSEMBLY_ITEM_ID
AND BOR.ORGANIZATION_ID = BOM.ORGANIZATION_ID
WHERE BOM.ORGANIZATION_ID = NVL(:P_ORG_ID,BOM.ORGANIZATION_ID)
AND EXISTS
(SELECT 'X'
FROM MTL_MATERIAL_TRANSACTIONS MMT
WHERE MMT.TRANSACTION_DATE >= ADD_MONTHS (SYSDATE,-12)
AND MSI.INVENTORY_ITEM_ID IS NOT NULL
)
GROUP BY BOM.ORGANIZATION_ID,
MSI.SEGMENT1,
MSIC.SEGMENT1
ORDER BY ORGANIZATION_CODE,
MSIC.SEGMENT1
My output is like this now:
I want to have another column which counts each item occurence in the output.
That's called conditional aggregation and you can do it with CASE EXPRESSION :
SELECT <col1>,<col2>..,
COUNT(CASE WHEN column ='Specific Val' THEN 1 END) as cnt
FROM YourTable
GROUP BY <col1>,<col2>..,
In MySQL this is also fine:
SUM(column = 'Specific Val')
Because expressions are treated as 1 and 0 .
wouldn't count(distinct column) work here since you're already using a group by
Would this be what you are looking for:
SELECT ColumnName, COUNT(*)
FROM TableName
GROUP BY ColumnName;
On the location of TableName you can also use a (SELECT ....).
You can also try this:
select count(*) from
(your query)
where column='value to be checked'

Adding up the rows of a column in a query

Here is my current query:
SELECT sac.cred, s.status, (SELECT NVL (csl.census_dates, tl.census_dates)
FROM schema.sections cs, schema.sections_ls csl, schema.terms tl
WHERE cs.course_sections_id = csl.course_sections_id(+)AND csl.pos(+) = 1 AND cs.term = tl.terms_id
AND tl.pos = 1 AND cs.course_sections_id = cs2.course_sections_id AND ROWNUM = 1)AS censusDate,
(SELECT NVL (p.ssn, 'xxx-xx-xxxx') FROM schema.person p
WHERE p.id = sac.person_id) AS ssn,
//schema.person_name(sac.person_id, 'FML') as fml,
//schema.person_name(sac.person_id, 'LF') as lf
FROM schema.student_acad_cred sac JOIN schema.statuses s
ON s.student_acad_cred_id = sac.student_acad_cred_id
JOIN schema.terms tl ON sac.term = tl.terms_id
JOIN schema.student_course_sec scs ON sac.student_course_sec = scs.student_course_sec_id
JOIN schema.course_sections cs2 ON scs.course_section = cs2.course_sections_id
JOIN schema.terms t ON tl.terms_id = t.terms_id
WHERE sac.person_id = '1111111111'
AND (s.status IN ('A', 'N') OR (s.status = 'D' AND final_grade IS NOT NULL))
AND s.pos = '1'AND tl.pos = '1' AND tl.terms_id = 'spring';
And here are the results:
cred status currentDate censusDate ssn
==== ====== =========== ========== ===
3 N 11/16/2011 12/15/2011 xxx-xx-xxxx
4 N 11/16/2011 12/15/2011 xxx-xx-xxxx
3 N 11/16/2011 12/15/2011 xxx-xx-xxxx
4 N 11/16/2011 12/15/2011 xxx-xx-xxxx
1 N 11/16/2011 12/15/2011 xxx-xx-xxxx
Okay, what I am trying to do is use sum() (or some other function) to add up all the credit hours that are pulled. So in this instance the sum of all cred hours would be '15'. Is there a way to do this in query? Ideally I would want something like this:
cred status currentDate censusDate ssn
==== ====== =========== ========== ===
15 N 11/16/2011 12/15/2011 xxx-xx-xxxx
The way to do this is to GROUP BY all of your other columns. Since you can't group by aliased columns directly (in Oracle and most RDMBSes), you have to wrap the whole thing in another query and do the grouping there.
SELECT SUM(cred), status, censusDate, ssn
FROM
(SELECT sac.cred, s.status,
(SELECT NVL (csl.census_dates, tl.census_dates)
FROM schema.sections cs, schema.sections_ls csl, schema.terms tl
WHERE cs.course_sections_id = csl.course_sections_id(+)AND csl.pos(+) = 1 AND cs.term = tl.terms_id
AND tl.pos = 1 AND cs.course_sections_id = cs2.course_sections_id AND ROWNUM = 1)AS censusDate,
(SELECT NVL (p.ssn, 'xxx-xx-xxxx') FROM schema.person p
WHERE p.id = sac.person_id) AS ssn,
//schema.person_name(sac.person_id, 'FML') as fml,
//schema.person_name(sac.person_id, 'LF') as lf
FROM schema.student_acad_cred sac JOIN schema.statuses s
ON s.student_acad_cred_id = sac.student_acad_cred_id
JOIN schema.terms tl ON sac.term = tl.terms_id
JOIN schema.student_course_sec scs ON sac.student_course_sec = scs.student_course_sec_id
JOIN schema.course_sections cs2 ON scs.course_section = cs2.course_sections_id
JOIN schema.terms t ON tl.terms_id = t.terms_id
WHERE sac.person_id = '1111111111'
AND (s.status IN ('A', 'N') OR (s.status = 'D' AND final_grade IS NOT NULL))
AND s.pos = '1'AND tl.pos = '1' AND tl.terms_id = 'spring')
GROUP BY status, censusDate, ssn;
This looks ugly, but doesn't actually have a horrible performance impact.
select groupcol, sum(cred)
from table1
group by rollup(groupcol)

Problem with SQL query involving XOR-like condition

Let's say we have a table (EnsembleMembers) in an SQL database with the following data. It lists the musicians which are part of various ensembles, along with their instruments.
EnsembleID (FK) MusicianID (FK) Instrument
----------------------------------------------
'1' '1' 'Clarinet'
'1' '4' 'Clarinet'
'1' '100' 'Saxophone'
'2' '200' 'Saxophone'
'2' '300' 'Saxophone'
'2' '320' 'Flute'
'99' '300' 'Clarinet'
I want to select the ensemble IDs where the ensemble has one or more saxophone or one or more clarinet players, but not both. I have tried the following SQL statement, but it is returning 1,2,2,99, rather than the expected 2,99.
SELECT e1.EnsembleID
FROM ensemblemembers e1
WHERE e1.Instrument = 'Saxophone'
OR e1.Instrument = 'Clarinet'
AND NOT EXISTS (SELECT *
FROM ensemblemembers e2
WHERE ( e1.Instrument = 'Saxophone'
AND e2.Instrument = 'Clarinet'
AND e1.EnsembleID = e2.EnsembleID)
OR ( e1.Instrument = 'Clarinet'
AND e2.Instrument = 'Saxophone'
AND e1.EnsembleID = e2.EnsembleID));
What am I doing wrong?
PS - I don't want to use DISTINCT for performance reasons.
SELECT EnsembleID
FROM EnsembleMembers
WHERE Instrument IN ('Saxophone', 'Clarinet')
GROUP BY EnsembleID
HAVING COUNT(DISTINCT Instrument) = 1
You can also use a FULL OUTER JOIN for this, but this type of join is not supported by MySQL and a few other minor databases.
SELECT COALESCE(e1.EnsembleID, e2.EnsembleID) AS EnsembleID
FROM EnsembleMembers e1 FULL OUTER JOIN EnsembleMembers e2
ON e1.EnsembleID = e2.EnsembleID
AND e1.Instrument = 'Saxophone'
AND e2.Instrument = 'Clarinet'
WHERE e1.EnsembleID IS NULL OR e2.EnsembleID IS NULL
If you need this to work without FULL OUTER JOIN, try this:
SELECT e1.EnsembleID, e1.Instrument
FROM EnsembleMembers e1 LEFT OUTER JOIN EnsembleMembers e2
ON e1.EnsembleID = e2.EnsembleID
AND e2.Instrument = 'Clarinet'
WHERE e1.Instrument = 'Saxophone' AND e2.EnsembleID IS NULL
UNION
SELECT e1.EnsembleID, e1.Instrument, e2.EnsembleID, e2.Instrument
FROM EnsembleMembers e1 LEFT OUTER JOIN EnsembleMembers e2
ON e1.EnsembleID = e2.EnsembleID
AND e2.Instrument = 'Saxophone'
WHERE e1.Instrument = 'Clarinet' AND e2.EnsembleID IS NULL;
In the future, please tag your question with the brand of RDBMS you use.
I assume you have a table called ENSEMBLES:
select E.id from ensembles E where exists (
select 1 from ensemblemembers M where E.id = M.ensembleid
and M.instrument in ('clarinet', 'saxophone')
) and not (
exists (
select 1 from ensemblemembers M where E.id = M.ensembleid
and M.instrument = 'clarinet'
) and exists (
select 1 from ensemblemembers M where E.id = M.ensembleid
and M.instrument = 'saxophone'
)
)
You want to avoid using DISTINCT, so one way to do it is by using the main ENSEMBLES table. From there, pick ensemble rows that have 'clarinet' OR 'saxophone'. Then the third step is to remove all ensemble rows that have 'clarinet' AND 'saxophone'.
Here is the most stupid solution (but I like it somehow):
SELECT EnsembleID FROM EnsembleMembers
MINUS
(
SELECT EnsembleID
FROM EnsembleMembers
WHERE Instrument = 'Saxophone'
INTERSECT
SELECT EnsembleID
FROM EnsembleMembers
WHERE Instrument = 'Clarinet' );
Here's how you could do the query using XOR:
select a.EnsembleID from
(
select max(EnsembleID) as EnsembleID,
max(case when Instrument = 'Saxophone' then 1 else 0 end) as Saxophone,
max(case when Instrument = 'Clarinet' then 1 else 0 end) as Clarinet
from
EnsembleMembers
group by EnsembleID
) a
where
a.Saxophone ^ a.Clarinet = 1