Want to filter SQL Server query - sql

Currently I am pulling out the Facilities where the permitType is 'Hazardous waste' and the licenseStatus is 'Open', but there will be cases where the facilities will have more than one permit type suppose a facility can have two permit types
Hazardous waste (status - OPEN)
AST (OPEN)
so I should not display this facility in my output if it other permit types (Status - OPEN) apart from the 'hazardous waste', but if the other permit type has status - CLOSE then my query should output the Facility i.e if AST(Status - CLOSE) then the facility should be pulled from the database.
I wrote the following query but not sure where to include the condition.
SELECT
e.facilityID
,f.organization_core AS 'Facility Name'
,f.address_full_core AS 'Facility Address'
,a.permitNumber AS 'Permit Number'
,b.permitName AS 'Permit Name'
,a.licenseStatus AS 'Permit Status'
,c.permitType AS 'Permit Type'
FROM
tblPermits a
LEFT JOIN
dbo.tblPermit_Names b ON a.permitID = b.permitID
LEFT JOIN
dbo.tblLKP_Permit_Facilities d ON a.permitID = d.permitID
LEFT JOIN
dbo.tblPermit_Types c ON a.permitTypeID = c.permitTypeID
LEFT JOIN
dbo.tblFacility e ON d.facilityID = e.facilityID
LEFT JOIN
dbo.tblAddresses f ON e.facilityAddressID = f.addressID
WHERE
a.permitTypeID IN (SELECT permitTypeID
FROM dbo.tblPermit_Types
WHERE permitType IN ('Hazardous Waste'))
AND a.licenseStatus = 'Open'
AND isNull(a.deleted, 0) = 0

I think the following query implements your rules. The idea is to focus on the facility and not on all the extra stuff in the tables that you have put in. You need to aggregate by facilityid so you can apply logic to all the permits issued for each one:
SELECT f.facilityID
FROM dbo.tblFacility f join
dbo.tblLKP_Permit_Facilities pf
on pf.facilityID = f.facilityId join
tblPermits p
on pf.permitID = p.permitID join
dbo.tblPermit_Types pt
ON pt.permitTypeID = p.permitTypeID
GROUP BY f.facilityID
HAVING SUM(case when pt.permitType IN ('Hazardous Waste') and p.licenseStatus = 'Open'
then 1 else 0
end) > 0 and
SUM(case when pt.permitType NOT IN ('Hazardous Waste') and p.licenseStatus = 'Close'
then 1 else 0
end) > 0;
Each condition in the having clause is applying one of your rules.

I'm a little confused as to your table structure, but this is what I think you should do.
Your where statement should be id in (Select id from table where status = open and count(id) = 1 group by facility)
AND Type in ('Hazardous Waste')
The first part of the where statement will limit all ids to those that are open with only one open type per facility, the second part limits it to just hazardous waste.
If you have a facility with 10 permits, but only one is active, it will pull it into the list, but if the active permit isn't hazardous waste, it will then exclude it.
Sorry I can't give you exact code.
Also, nix as many of those outer joins as you can. Inner joins are faster, and are more likely to represent the data you want.

Related

SQL query with GROUP BY and HAVING COUNT(condition) in ORACLE

I have three tables: temp, product and feed.
I'll show on example:
select ri.id from temp ri
inner join product i on ri.id = to_char(i.val)
inner join feed f on f.product_id = i.product_id
where i.status = 'Finished'
and f.type = 'Type'
group by f.feed_id, ri.id
having COUNT(f.status = 'SUCCESS') < 1;
so I tried to get all ids from temp that have f.type = 'Type'. Problem is that for one feed.feed_id can be many rows because I could retrigger it 5 times and let's say 4 times it crashed but at 5th attempt it was SUCCESS, so for one feed.feed_id I would have 5 rows and only one would be with f.status = SUCCESS.
Error which I receive for this query is ORA-00907: missing right parenthesis which makes me totally confused.
feed table:
feed_id, status, type
I am interested in all feed_id which don't have even one status='SUCCESS' for type='TYPE'
You can't COUNT a boolean expression in Oracle, you can use a CASE expression instead e.g.
HAVING COUNT(CASE WHEN f.status = 'SUCCESS' THEN 1 END) < 1
This expression returns NULL when the condition is false, so it will only count the rows for which the condition is true (since COUNT of an expression ignores NULL values).
Note also (as #GordonLinoff points out in the comments) that since COUNT cannot return a negative number, it is cleaner (and would be more efficient) to simply compare the result for equality with 0, rather than being less than 1:
HAVING COUNT(CASE WHEN f.status = 'SUCCESS' THEN 1 END) = 0

SQL: Split rows with same ID into columns + left join

I have a cs cart database and I am trying to select all the attributes for all the products, the problem is that for each separate attribute for a product, my query creates a new row, I want to to have a single row for each products that has all the attributes into columns.
This is my query right now:
SELECT a.product_id, b.variant, c.description, d.product_code
FROM cscart_product_features_values a
LEFT JOIN cscart_product_feature_variant_descriptions b ON a.variant_id = b.variant_id
LEFT JOIN cscart_product_features_descriptions c ON a.feature_id = c.feature_id
LEFT JOIN cscart_products d ON a.product_id = d.product_id
After I run the query, I get the following result:
product_id;"variant";"description";"product_code"
38;"1st";"Grade Level";"750"
38;"Math";"Subject Area";"750"
38;"Evan-Moor";"Publisher";"750"
etc next product
What I want is this:
product_id;"product_code";"Grade Level";"Subject Area";"Publisher"
38;"750";"1st";"Math";"Evan-Moor"
etc next product
We only have 3 type of attributes: Grade Level, Subject Area and Publisher.
Any ideas how to improve my query and achieve this? I would be happy even with concatenating all 3 attributes in one column, delimited by ",".
This is a generic SQL solution using GROUP BY and MAX(case expression) to achieve the transformation of 3 rows into a single row with the 3 columns.
SELECT
v.product_id
, p.product_code
, MAX(CASE WHEN fd.description = 'Grade Level' THEN vd.variant END) AS GradeLevel
, MAX(CASE WHEN fd.description = 'Subject Area' THEN vd.variant END) AS SubjectArea
, MAX(CASE WHEN fd.description = 'Publisher' THEN vd.variant END) AS Publisher
FROM cscart_products p
LEFT JOIN cscart_product_features_values v ON p.product_id = v.product_id
LEFT JOIN cscart_product_feature_variant_descriptions vd ON v.variant_id = vd.variant_id
LEFT JOIN cscart_product_features_descriptions fd ON v.feature_id = fd.feature_id
GROUP BY
v.product_id
, p.product_code
This approach should work on just about any SQL database.
Note also that I have changed the order of tables because I presume there has to be a row in cscart_products, but there might not be related rows in the other tables.
I have also changed the aliases, personally I do not care for aliaes based on the order of use in a query (e.g. I just changed the order so I had to change all references). I have use 'p' = product, 'v' = variant, 'vd' = variant description & 'fd' = feature description' - with such a convention for aliases I can re-arrange the query without changing every reference.

Query from multiple tables with multiple where conditions in the tables

I'm trying to get a count of all speakers who are active regarding that item as well as the total of speakers who correlate to a certain item. The first LEFT JOIN for the total speakers works, but the other for ONLY the active speakers regarding that item doesn't, any help is appreciated. The SQLFiddle is here
http://sqlfiddle.com/#!3/b579d/1
But when I try to add in the portion where you would get the number of active speakers
(LEFT JOIN (SELECT COUNT (tbl_SpeakerCard_Log.SpeakerName)
WHERE tbl_Speaker_Log.Spoken = 0)
ON tbl_AgendaList.AID = tbl_SpeakerCard_Log.AID)
under the previous LEFT JOIN I get an error. I'm 100% sure the query is wrong in some form, but I'm not sure how to approach it.
*NOTE: Spoken/Active are interchangeable, I just use different wording to clarify what I'm looking for.
EDIT: This is the desired output
http://imgur.com/yP1FKxg
You can use conditional aggregation to do this:
SELECT
AgendaList.AID,
AgendaList.Item,
COUNT(SpeakerList.SPID) as SpeakerTotal,
SUM(CASE WHEN SpeakerList.Spoken = 0 THEN 1 ELSE 0 END) as ActiveSpeakers
FROM AgendaList
LEFT JOIN SpeakerLIST ON AgendaList.AID = SpeakerList.AID
GROUP BY AgendaList.AID, AgendaList.Item;
Sample SQL Fiddle
Or you could use count instead of sum (which might be clearer):
COUNT(CASE WHEN Spoken = 0 THEN Spoken END) as ActiveSpeakers
SQL FIDDLE
WITH sTotal AS (
SELECT AgendaList.AID, AgendaList.Item, COUNT( SpeakerList.SPID) as SpeakerTotal
FROM AgendaList
LEFT JOIN SpeakerLIST ON AgendaList.AID = SpeakerList.AID
GROUP BY AgendaList.AID, AgendaList.Item
),
sActive AS (
SELECT AgendaList.AID, AgendaList.Item, COUNT( SpeakerList.SPID) as SpeakerActive
FROM AgendaList
LEFT JOIN SpeakerLIST ON AgendaList.AID = SpeakerList.AID
WHERE SpeakerLIST.Spoken = 0
GROUP BY AgendaList.AID, AgendaList.Item
)
SELECT sTotal.*, sActive.SpeakerActive
FROM sTotal left join
sActive on sTotal.AID = sActive.AID

Joining a derived table postgres

I have 4 tables:
Competencies: a list of obviously competencies, static and a library
Competency Levels: refers to an associated group of competencies and has a number of competencies I am testing for
call_competency: a list of all 'calls' that have recorded the specified competency
competency_review_status: proving whether each call_competency was reviewed
Now I am trying to write this query to count a total and spit out the competency, id and whether a user has reached the limit. Everything works except for when I add the user. I am not sure what I am doing wrong, once I limit call competency by user in the where clause, I get a small subset that ONLY exists in call_competency returned when I want the entire list of competencies.
The competencies not reached should be false, ones recorded appropriate number true. A FULL list from the competency table.
I added the derived table, not sure if this is right, obviously it doesn't run properly, not sure what I'm doing wrong and I'm wasting time. Any help much appreciated.
SELECT comp.id, comp.shortname, comp.description,
CASE WHEN sum(CASE WHEN crs.grade = 'Pass' THEN 1 ELSE CASE WHEN crs.grade = 'Fail' THEN -1 ELSE 0 END END) >= comp_l.competency_break_level
THEN TRUE ELSE FALSE END
FROM competencies comp
INNER JOIN competency_levels comp_l ON comp_l.competency_group = comp.competency_group
LEFT OUTER JOIN (
SELECT competency_id
FROM call_competency
WHERE call_competency.user_id IN (
SELECT users.id FROM users WHERE email= _studentemail
)
) call_c ON call_c.competency_id = comp.id
LEFT OUTER JOIN competency_review_status crs ON crs.id = call_competency.review_status_id
GROUP BY comp.id, comp.shortname, comp.description, comp_l.competency_break_level
ORDER BY comp.id;
(Shooting from the hip, no installation to test)
It looks like the below should do the trick. You apparently had some of the joins mixed up, with a column from a relation that was not referenced. Also, the CASE statement in the main query could be much cleaner.
SELECT comp.id, comp.shortname, comp.description,
(sum(CASE WHEN crs.grade = 'Pass' THEN 1 WHEN crs.grade = 'Fail' THEN -1 ELSE 0 END) >= comp_l.competency_break_level) AS reached_limit
FROM competencies comp
JOIN competency_levels comp_l USING (competency_group)
LEFT JOIN (
SELECT competency_id, review_status_id
FROM call_competency
JOIN users ON id = user_id
WHERE email = _studentemail
) call_c ON call_c.competency_id = comp.id
LEFT JOIN competency_review_status crs ON crs.id = call_c.review_status_id
GROUP BY comp.id, comp.shortname, comp.description
ORDER BY comp.id;

SQL Display Distinct records and include a field if certain data is found

What I'm trying to accomplish is display distinct data but also display a field on each row if a particular row has a certain data.
The thing thats confusing me is the fact that I still need it to be distinct and if I attempt to do another join i get more rows..
I just wish to keep the same results i'm retrieving but with an additional column that tells me - This equipment (row) needs repairs because at least one of its properties stated so... Hope this makes sense, not sure if I'm explaining myself clearly here.
The Main Table (Inspection Table)
In the above table, Notice FK_Sequence Each entry has around 17 which the user is required to answer OK or REPAIR (this is the FK_Status)
My current Query is the following and results just an Employee and the equipment they worked on.
SELECT DISTINCT
a.EnteredDate,
bb.EmployeeId,
bb.EmployeeName,
dd.EquipmentId,
dd.EquipmentName
FROM dbo.PIT_Inspection a
INNER JOIN dbo.EmployeeName bb
ON a.FK_EmployeeName = bb.PK_EmployeeName
INNER JOIN dbo.EquipmentName dd
ON a.FK_EquipmentName = dd.PK_EquipmentName
Results for above query:
But then here is where my question comes in. Notice the Main Table - FK_Status of 2 on Line 19.. I would like to detect this and for this particular Employee Display Repair in an additional column in the table above named StatusName.
You can do this by using GROUP BY instead of DISTINCT, then you can use a conditional count to see how many rows have a status of 2, if it is more than none then display REPAIR
SELECT a.EnteredDate,
bb.EmployeeId,
bb.EmployeeName,
dd.EquipmentId,
dd.EquipmentName,
StatusName = CASE WHEN COUNT(CASE WHEN a.FK_Status = 2 THEN 1 END) > 0
THEN 'REPAIR'
ELSE ''
END
FROM dbo.PIT_Inspection a
INNER JOIN dbo.EmployeeName bb
ON a.FK_EmployeeName = bb.PK_EmployeeName
INNER JOIN dbo.EquipmentName dd
ON a.FK_EquipmentName = dd.PK_EquipmentName
GROUP BY a.EnteredDate, bb.EmployeeId, bb.EmployeeName, dd.EquipmentId, dd.EquipmentName;
Try this:
SELECT
a.EnteredDate,
bb.EmployeeId,
bb.EmployeeName,
dd.EquipmentId,
dd.EquipmentName,
CASE WHEN SUM(CASE FK_Status WHEN 2 THEN 1 ELSE 0 END) > 0
THEN 'Repair' ELSE 'OK' END AS StatusName
FROM dbo.PIT_Inspection a
INNER JOIN dbo.EmployeeName bb
ON a.FK_EmployeeName = bb.PK_EmployeeName
INNER JOIN dbo.EquipmentName dd
ON a.FK_EquipmentName = dd.PK_EquipmentName
GROUP BY
a.EnteredDate,
bb.EmployeeId,
bb.EmployeeName,
dd.EquipmentId,
dd.EquipmentName
Have the query with the distinct as a sub query, then join to get the "additional information". Something along the lines of:
SELECT (your orig fields, but take from inspection where you took from a)
FROM
(SELECT DISTINCT a.FK_EmployeeName, a.EnteredDate, FK_EquipmentName
FROM dbo.PIT_Inspection a) inspection
INNER JOIN dbo.EmployeeName bb
ON inspection.FK_EmployeeName = bb.PK_EmployeeName
INNER JOIN dbo.EquipmentName dd
ON inspection.FK_EquipmentName = dd.PK_EquipmentName