SQL query question. Extracting data met for one of two conditions but not both - sql

I'm extracting student data who have completed a list of courses for degree requirements. One of the courses on the list is equivalent to another course, so if a student completes both equivalent courses, it can only be counted once towards a degree. I need to extract data on students who completed the list of courses, while filtering for just one of the equivalent courses.
Where am I going wrong?
I've tried different OR and AND NOT clauses but I can't seem to get the result that I need
use coll18_live
select ENR_STUDENT_ID, ENR_TERM, CRS_NAME, ENR_GRADE
from dbo.CA320_ENROLLMENT_VIEW_N03
WHERE ENR_CENSUS_REG_FLAG = 'Y'
and ENR_TERM in ('14/FA', '15/SP')
and not (CRS_NAME = 'BUSI-105' and CRS_NAME = 'ENGL-120')
and CRS_NAME in ('ACCT-120', 'ACCT-125', 'BUSI-100', 'BUSI-103', 'BUSI-105', 'ENGL-120')
I expect the output to show students who completed ACCT-120, ACCT-12, BUSI-100, BUSI-103, and BUSI-105 or ENGL-120 (but not both BUSI-105 or ENGL-120)

I think you want aggregating with a having clause. You cannot do this with a WHERE, because the information you want is (apparently) in different rows:
select ENR_STUDENT_ID
from dbo.CA320_ENROLLMENT_VIEW_N03
where ENR_CENSUS_REG_FLAG = 'Y' AND
ENR_TERM in ('14/FA', '15/SP')
group by ENR_STUDENT_ID
having sum(case when CRS_NAME in ('ACCT-120', 'ACCT-125', 'BUSI-100', 'BUSI-103') then 1 else 0 end) = 4 and
sum(case when CRS_NAME in ('BUSI-105', 'ENGL-120') then 1 else 0 end) > 0;

Related

How to output total number of professions in SQL based on 4 tables

I have the following tables available through this link:
tables.
I'm trying to do a query where I list out the degrees (profession) and the counts associated with that profession. If the degree is listed more than twice, it should output 'Popular Degree'. I coded:
select profession, count(profession_id), count(profession_id) > 2 as Popular
from Profession
where profession_id in
(select profession_id from provider_profession)
group by profession
I get an output of this, which is wrong:
My query result
I am not sure how to query the result.
replace count(profession_id) > 2 as Popular with (case when count(profession_id) > 2 then 1 else 0 end) as Popular
Try this:
select p.profession,
count(pp.provider_id),
case
when count(pp.provider_id)>2 then 'Popular degree'
else ''
end as DegreePopularity
from profession p inner join provider_profession pp on p.profession_id=pp.profession_id
group by p.profession
I have tried to keep the answer as close to ANSI sql as possible, though only tested it out on a sql server

How to to get two columns of data unrelated to each other in one sql query statement?

I need to get a state level count on number of services. For the purposes of this I only have two services. The first column is the states, the second column is the first services and the third column is the second service. What I am struggling with is to have the second and third column show up on the results in one query. Here is my code:
SELECT Distinct allstates.Name, count (data.StateName) as CareCase_Management_Services, count(data.StateName) Caregiver_Support_Services
From
(select distinct Name from USstate) allstates
Left Join
Client2017 data
on
allstates.Name = data.StateName and
data.FiscalYear = 2017 and
data.SrvstartCareCaseMgmtCode NOT IN('999','', '998') and
data.SrvstartCaregiverSuppCode NOT IN('999','', '998')
GROUP BY allstates.Name
ORDER BY allstates.Name ASC
I understand that you are looking to compute, for each state, the count of services that match certain criteria. There are two types of services, stored in two different columns.
If so, your query could be simplified using conditional aggregation :
SELECT
allstates.Name,
SUM(CASE WHEN c.SrvstartCareCaseMgmtCode NOT IN ('999', '', '998') THEN 1 ELSE 0 END) CareCase_Management_Services,
SUM(CASE WHEN c.SrvstartCaregiverSuppCode NOT IN ('999', '', '998') THEN 1 ELSE 0 END) Caregiver_Support_Services
FROM
(SELECT DISTINCT Name FROM USstate) s
LEFT JOIN Client2017 c ON s.Name = c.StateName AND c.FiscalYear = 2017
GROUP BY allstates.Name
With this technique, each service is counted according to its own logic ; when conditions are met, the record is counted in (1 is added to the SUM()), else it is ignored (+ 0).
NB : do you really have duplicated state names in USstate ? if no, you can replace subquery (SELECT DISTINCT Name FROM USstate) s with just USstate

sql - return all rows only if there is no field equal to A?

I'm a bit stuck. I don't have my current SQL handy, but I'll try to be clear. Say I have a table of student IDs along with a course number and their grade. I want to return students only with no grades equal to A. I don't want just rows that aren't equal to A, but I am trying to find all student IDs with no associated A grades, otherwise students with at least one A will not be returned.
How might I tackle this problem? I'm fairly new to SQL. Thanks
EDIT: Okay, now that I have the actual SQL I can drop my terrible analogy.
SELECT ALL
ITEMS.QTY_ONHAND AS QTY_ONHAND,
ITEMS.ITEM_ID AS ITEM_ID_I0,
MEDORDER.MO_STAT AS MOMO_STAT,
UPPER(ITEMS.ITEM_ID) AS ITEM_ID_IC,
ITEMS.RX_DISP AS RX_DISP,
OMNIS.OMNI_ID AS OMNI_ID,
MEDORDER.ITEM_ID AS MOITEM_ID
FROM ITEMS ITEMS,
MEDORDER MEDORDER,
OMNIS OMNIS,
"PATIENTS" PATIENTS
WHERE (ITEMS.OMNI_STID = OMNIS.OMNI_STID) AND
(PATIENTS.PAT_ID = MEDORDER.PAT_ID) AND
(OMNIS.AREA = PATIENTS.AREA) AND (UPPER(ITEMS.ITEM_NAME) LIKE '%Doxycycline%'
AND MEDORDER.ITEM_ID = UPPER(ITEMS.ITEM_ID)
AND MEDORDER.MO_STAT='A')
ORDER BY ITEMS.QTY_ONHAND DESC, OMNIS.OMNI_ID, MEDORDER.ITEM_ID
What I have here is a location, omni_id. My query is looking for every omni_id that has this item_id. This will return multiple results for each omni_id corresponding to multiple medorders for the same item_id. What I want to do, is only return omni_ids that have 0 results for any medorder.mo_stat equal to 'A'. For example, omni_id 3W will have 3 returns, wth medorder_mo_stat equal to A, C, and C. And another, 4S, with medorder.mo_stats of C, C, C. I only want my query to return that 4S group, because it has no medorder.mo_stats of 'A'.
Sorry about the bad explanation.. I'm multitasking a few projects right now and my SQL-fu is not very strong, I'm not sure how to implement the below solutions to get what I'm looking for.
Thanks a ton in advance
Based you on your update - I assume this may help, but I'm still not sure I understand your schema, so maybe I am missing something...
SELECT
OMNIS.OMNI_ID AS OMNI_ID,
COUNT(MEDORDER.ITEM_ID) AS A_COUNT
FROM
ITEMS
JOIN
OMNIS
ON (ITEMS.OMNI_STID = OMNIS.OMNI_STID)
JOIN
PATIENTS
ON (OMNIS.AREA = PATIENTS.AREA)
LEFT JOIN
MEDORDER
ON (MEDORDER.ITEM_ID = UPPER(ITEMS.ITEM_ID)
AND (PATIENTS.PAT_ID = MEDORDER.PAT_ID)
AND (MEORDER.MO_STAT = 'A')
WHERE
UPPER(ITEMS.ITEM_NAME) LIKE '%Doxycycline%'
GROUP BY
OMNIS.OMNI_ID
HAVING
COUNT(MEDORDER.ITEM_ID) = 0
^EDIT^
Lost of ways to solve this one. I would do this:
SELECT
StudentID,
MAX(CASE Grade WHEN 'A' THEN 1 ELSE 0 END) AS HasAnA
FROM
MyTable
GROUP BY
StudentID
HAVING
MAX(CASE Grade WHEN 'A' THEN 1 ELSE 0 END) = 0
Or even just this depending on your table design:
SELECT DISTINCT
StudentID
FROM
MyTable
WHERE
Grade != 'A'

Sum in Decode statement?

I have to provide counts for different activities, some of the columns are from some table but few I have to take by joining other tables. And in the last column I have to add counts *of 5 columns togather in one field*.Please see my query below and advice the best way to achieve my results :)
SELECT web. OID,web. MARKETING_GROUP,
SUM(DECODE(WEB.EVENT_TYPE,5,WEB.ACTIVITY_COUNT,0)) AS DISCUSSIONCOMMENT ,
SUM(DECODE(WEB.EVENT_TYPE,6,WEB.ACTIVITY_COUNT,0)) AS DISCUSSIONSTART ,
SUM(DECODE(WEB.EVENT_TYPE,7,WEB.ACTIVITY_COUNT,0)) AS DISCUSSIONVIEW,
SUM(case when o.when _clicked is not null then c(*))AS clickcount,
**SUM(case when WEB.EVENT_TYPE in(5,6,7,8)then WEB.ACTIVITY_COUNT +c.count(*))as Total** --------- This is where I am getting stuck and confused???
from GMMI_AIR.WEB_ACTIVITY_FCT WEB join GMMI_AIR.COUPON_WEB_ACTIVITY C
on WEB.OID_WEB_ACTIVITY_FCT = C.OID_COUPON_WEB_ACTIVITY
I am really stuck as the table which is joined doesn'thave field named activity_count or activity_type so to see the counts I can only do count(*) but to add it all other fileds in one column and sum it up is very confusing??
Any help??/
SELECT web. OID,web. MARKETING_GROUP,
SUM(DECODE(WEB.EVENT_TYPE,5,WEB.ACTIVITY_COUNT,0)) AS DISCUSSIONCOMMENT ,
SUM(DECODE(WEB.EVENT_TYPE,6,WEB.ACTIVITY_COUNT,0)) AS DISCUSSIONSTART ,
SUM(DECODE(WEB.EVENT_TYPE,7,WEB.ACTIVITY_COUNT,0)) AS DISCUSSIONVIEW,
SUM(case when o.when _clicked is not null then c(*))AS clickcount,
SUM(case when WEB.EVENT_TYPE in(5,6,7,8)then WEB.ACTIVITY_COUNT END) +c.count(*) as Total
from GMMI_AIR.WEB_ACTIVITY_FCT WEB join GMMI_AIR.COUPON_WEB_ACTIVITY C
on WEB.OID_WEB_ACTIVITY_FCT = C.OID_COUPON_WEB_ACTIVITY
GROUP BY web. OID,web. MARKETING_GROUP;

How would I write this SQL query?

I have the following tables:
PERSON_T DISEASE_T DRUG_T
========= ========== ========
PERSON_ID DISEASE_ID DRUG_ID
GENDER PERSON_ID PERSON_ID
NAME DISEASE_START_DATE DRUG_START_DATE
DISEASE_END_DATE DRUG_END_DATE
I want to write a query that takes an input of a disease id and returns one row for each person in the database with a column for the gender, a column for whether or not they have ever had the disease, and a column for each drug which specifies if they took the drug before contracting the disease. I.E. true would mean drug_start_date < disease_start_date. False would mean drug_start_date>disease_start_date or the person never took that particular drug.
We currently pull all of the data from the database and use Java to create a 2D array with all of these values. We are investigating moving this logic into the database. Is it possible to create a query that will return the result set as I want it or would I have to create a stored procedure? We are using Postgres, but I assume an SQL answer for another database will easily translate to Postgres.
Based on the info provided:
SELECT p.name,
p.gender,
CASE WHEN d.disease_id IS NULL THEN 'N' ELSE 'Y' END AS had_disease,
dt.drug_id
FROM PERSON p
LEFT JOIN DISEASE d ON d.person_id = p.person_id
AND d.disease_id = ?
LEFT JOIN DRUG_T dt ON dt.person_id = p.person_id
AND dt.drug_start_date < d.disease_start_date
..but there's going to be a lot of rows that will look duplicate except for the drug_id column.
You're essentially looking to create a cross-tab query with the drugs. While there are plenty of OLAP tools out there that can do this sort of thing (among all sorts of other slicing and dicing of the data), doing something like this in traditional SQL is not easy (and, in general, impossible to do without some sort of procedural syntax in all but the simplest scenarios).
You essentially have two options when doing this with SQL (well, more accurately, you have one option, and another more complicated but flexible option that derives from it):
Use a series of CASE statements in your query to produce columns that are representative of each individual drug. This requires knowing the list of variable values (i.e. drugs) ahead of time
Use a procedural SQL language, such as T-SQL, to dynamically construct a query that uses case statements as described above, but along with obtaining that list of values from the data itself.
The two options essentially do the same thing, you're just trading simplicity and ease of maintenance for flexibility in the second option.
For example, using option 1:
select
p.NAME,
p.GENDER,
(case when d.DISEASE_ID is null then 0 else 1 end) as HAD_DISEASE,
(case when sum(case when dr.DRUG_ID = 1 then 1 else 0 end) > 0 then 1 else 0 end) as TOOK_DRUG_1,
(case when sum(case when dr.DRUG_ID = 2 then 1 else 0 end) > 0 then 1 else 0 end) as TOOK_DRUG_2,
(case when sum(case when dr.DRUG_ID = 3 then 1 else 0 end) > 0 then 1 else 0 end) as TOOK_DRUG_3
from PERSON_T p
left join DISEASE_T d on d.PERSON_ID = p.PERSON_ID and d.DISEASE_ID = #DiseaseId
left join DRUG_T dr on dr.PERSON_ID = p.PERSON_ID and dr.DRUG_START_DATE < d.DISEASE_START_DATE
group by p.PERSON_ID, p.NAME, p.GENDER, d.DISEASE_ID
As you can tell, this gets a little laborious as you get outside of just a few potential values.
The other option is to construct this query dynamically. I don't know PostgreSQL and what, if any, procedural capabilities it has, but the overall procedure would be this:
Gather list of potential DRUG_ID values along with names for the columns
Prepare three string values: the SQL prefix (everything before the first drug-related CASE statement, the SQL stuffix (everything after the last drug-related CASE statement), and the dynamic portion
Construct the dynamic portion by combining drug CASE statements based upon the previously retrieved list
Combine them into a single (hopefully valid) SQL statement and execute