SQL Server 2008 Pivot table aggregate function issue - sql

I have this query and I am trying to group by surveyname but im getting this error:
Msg 8120, Level 16, State 1, Line 1
Column 'pvt.Follow Up' is invalid in the select list because it is not contained in either an aggregate function or the GROUP BY clause.
This is the query:
SELECT
surveyname, [Follow Up] AS Follow_Up, [Ambiance] AS Ambiance,
[Consultation] AS Consultation, [Procedure/Service] AS Procedure_Service
FROM
(SELECT
s.name surveyname, q.question, subq.answer subquestion,aw.answerweight,
aw.score, rc.categoryname, sc.cweight
FROM survey.dbo.results r
JOIN survey.dbo.questions q ON r.questionidfk = q.id
LEFT JOIN survey.dbo.answers subq ON r.itemidfk = subq.id
LEFT JOIN survey.dbo.answers a ON r.answeridfk = a.id
JOIN survey.dbo.surveys s ON q.surveyidfk = s.id
join sigweb.dbo.survey_types_main stm on s.id = stm.surveyidfk
join survey.dbo.survey_results sr on r.owneridfk = sr.ownerid
join sigweb.dbo.BosleySurvey bs on bs.contactid = sr.contactid and stm.clientsurveytypeid = bs.surveytype
join sigweb.dbo.contact c on sr.contactid = c.contactid
join sigweb.dbo.patient p on p.contactid = c.contactid
join sigweb.dbo.doctor d on p.doctorid = d.doctorid
join sigweb.dbo.survey_tracking st on st.contactid = c.contactID and st.surveytypeid = stm.surveytypeid
left join survey.dbo.answerweighting aw on isnull(r.itemidfk, r.questionidfk) = aw.questionitemidfk and r.answeridfk = aw.answeridfk
left join survey.dbo.rating_categories rc on aw.categoryidfk = rc.id
left join survey.dbo.survey_categories sc on aw.categoryidfk = sc.categoryidfk and s.id = sc.surveyidfk
where
aw.answerWeight is not null) ps
PIVOT
(
AVG(score)
FOR categoryname IN
( [Follow Up], [Ambiance], [Consultation], [Procedure/Service])
) AS pvt
group by surveyname
This is an example of the results im getting
SURVEYNAME FOLLOW_UP Ambiance Consultation Procedure_Service
Review NULL NULL NULL 9.81
Review 9.54 NULL NULL NULL
Consultation 5 NULL NULL NULL
Consultation NULL 5 NULL NULL
Consultation NULL 5 NULL NULL
Consultation NULL 5 NULL NULL
Consultation NULL 5 NULL NULL
Consultation NULL 5 NULL NULL
Consultation NULL NULL 5 NULL
Consultation 5 NULL NULL NULL
Consultation NULL NULL 5 NULL
This is an example of the data before the pivot:
Review 6 Follow Up
Review 9 Procedure/Service
Consultation 5 Ambiance
Consultation 5 Ambiance
Consultation 5 Ambiance
Consultation 5 Ambiance
Consultation 5 Ambiance
Consultation 5 Ambiance
Consultation 5 Consultation
Consultation 5 Consultation
The idea is to group by the surveyname and have only two results in the end.

It appears that you are including too many columns in the inner SELECT, try to remove the columns:
q.question, subq.answer subquestion, aw.answerweight, sc.cweight
They are most likely making the rows DISTINCT so the GROUP BY does not work properly. So your query will be:
SELECT surveyname,
[Follow Up] AS Follow_Up,
[Ambiance] AS Ambiance,
[Consultation] AS Consultation,
[Procedure/Service] AS Procedure_Service
FROM
(
SELECT s.name surveyname,
aw.score,
rc.categoryname,
FROM survey.dbo.results r
JOIN survey.dbo.questions q
ON r.questionidfk = q.id
LEFT JOIN survey.dbo.answers subq
ON r.itemidfk = subq.id
LEFT JOIN survey.dbo.answers a
ON r.answeridfk = a.id
JOIN survey.dbo.surveys s
ON q.surveyidfk = s.id
join sigweb.dbo.survey_types_main stm
on s.id = stm.surveyidfk
join survey.dbo.survey_results sr
on r.owneridfk = sr.ownerid
join sigweb.dbo.BosleySurvey bs
on bs.contactid = sr.contactid
and stm.clientsurveytypeid = bs.surveytype
join sigweb.dbo.contact c
on sr.contactid = c.contactid
join sigweb.dbo.patient p
on p.contactid = c.contactid
join sigweb.dbo.doctor d on p.doctorid = d.doctorid
join sigweb.dbo.survey_tracking st
on st.contactid = c.contactID
and st.surveytypeid = stm.surveytypeid
left join survey.dbo.answerweighting aw
on isnull(r.itemidfk, r.questionidfk) = aw.questionitemidfk
and r.answeridfk = aw.answeridfk
left join survey.dbo.rating_categories rc
on aw.categoryidfk = rc.id
left join survey.dbo.survey_categories sc
on aw.categoryidfk = sc.categoryidfk and s.id = sc.surveyidfk
where aw.answerWeight is not null
) ps
PIVOT
(
AVG(score)
FOR categoryname IN
( [Follow Up], [Ambiance], [Consultation], [Procedure/Service])
) AS pvt

I am not sure where the error is coming from in what you have posted (I assume it is when you try and add GROUP BY SurveyName to the end of the query you have posted), but you need to remove the redundant columns from your subquery, so you only select the 3 columns you need, surveyname, score, and categoryname:
SELECT
surveyname, [Follow Up] AS Follow_Up, [Ambiance] AS Ambiance,
[Consultation] AS Consultation, [Procedure/Service] AS Procedure_Service
FROM
(SELECT
s.name surveyname, aw.score, rc.categoryname
FROM survey.dbo.results r
JOIN survey.dbo.questions q ON r.questionidfk = q.id
LEFT JOIN survey.dbo.answers subq ON r.itemidfk = subq.id
LEFT JOIN survey.dbo.answers a ON r.answeridfk = a.id
JOIN survey.dbo.surveys s ON q.surveyidfk = s.id
join sigweb.dbo.survey_types_main stm on s.id = stm.surveyidfk
join survey.dbo.survey_results sr on r.owneridfk = sr.ownerid
join sigweb.dbo.BosleySurvey bs on bs.contactid = sr.contactid and stm.clientsurveytypeid = bs.surveytype
join sigweb.dbo.contact c on sr.contactid = c.contactid
join sigweb.dbo.patient p on p.contactid = c.contactid
join sigweb.dbo.doctor d on p.doctorid = d.doctorid
join sigweb.dbo.survey_tracking st on st.contactid = c.contactID and st.surveytypeid = stm.surveytypeid
left join survey.dbo.answerweighting aw on isnull(r.itemidfk, r.questionidfk) = aw.questionitemidfk and r.answeridfk = aw.answeridfk
left join survey.dbo.rating_categories rc on aw.categoryidfk = rc.id
left join survey.dbo.survey_categories sc on aw.categoryidfk = sc.categoryidfk and s.id = sc.surveyidfk
where
aw.answerWeight is not null) ps
PIVOT
(
AVG(score)
FOR categoryname IN
( [Follow Up], [Ambiance], [Consultation], [Procedure/Service])
) AS pvt
In the background you are also grouping your end results by q.question, subq.answer subquestion,aw.answerweight, sc.cweight because they are included in the subquery, but because the are not in the select list you are not seeing immediately the effect this is having.

Related

SQL SUM columns from different tables

Good Afternoon,
I currently have the query:
SELECT erp_user.login,
SUM(invoice_header.invoice_amount) as 'Invoices Billed'
FROM erp_user
LEFT JOIN order_header ON erp_user.erp_user_id = order_header.req_by
LEFT JOIN invoice_instruct_header ON order_header.order_id = invoice_instruct_header.order_id
LEFT JOIN invoice_header ON invoice_instruct_header.instruct_id = invoice_header.instruct_no
WHERE erp_user.supervisor_id IS NOT NULL AND user_id_type = 'I' AND erp_user.company_id IS NOT NULL AND erp_user.is_active = 1
GROUP BY erp_user.login
It gives me a list of total billing in our system by employee where the employee is signed to a job on the job header.
I would love to add the total amount of open PO's to this query so I added:
SELECT erp_user.login, SUM(invoice_header.invoice_amount) as 'Invoices Billed', sum(po_header.po_amount) AS "Open PO's"
FROM erp_user
LEFT JOIN order_header ON erp_user.erp_user_id = order_header.req_by
LEFT JOIN invoice_instruct_header ON order_header.order_id = invoice_instruct_header.order_id
LEFT JOIN invoice_header ON invoice_instruct_header.instruct_id = invoice_header.instruct_no
LEFT JOIN po_header ON order_header.order_id = po_header.order_id
WHERE erp_user.supervisor_id IS NOT NULL AND user_id_type = 'I' AND erp_user.company_id IS NOT NULL AND erp_user.is_active = 1 AND po_header.status = 1
GROUP BY erp_user.login
ORDER BY "Open PO's"
That query gives me numbers in my Open PO's column, but they are incorrect and I'm at the point now where I can't figure out how to troubleshoot this.
Can someone please point me in the right direction? I don't mind doing the work, just need a pointer. Thanks!
Please be aware of conbination of Left join and Where clause.
SELECT erp_user.login
, SUM(invoice_header.invoice_amount) as 'Invoices Billed'
, sum(CASE WHEN po_header.status = 1 THEN po_header.po_amount ELSE 0 END) AS "Open PO's"
FROM erp_user
LEFT JOIN order_header ON erp_user.erp_user_id = order_header.req_by
LEFT JOIN invoice_instruct_header ON order_header.order_id = invoice_instruct_header.order_id
LEFT JOIN invoice_header ON invoice_instruct_header.instruct_id = invoice_header.instruct_no
LEFT JOIN po_header ON order_header.order_id = po_header.order_id
WHERE erp_user.supervisor_id IS NOT NULL
AND user_id_type = 'I'
AND erp_user.company_id IS NOT NULL
AND erp_user.is_active = 1
GROUP BY erp_user.login
ORDER BY "Open PO's";
If po_header joins to order_header, then in your original query it would be repeating each po_header for each invoice_header as well (leading to the incorrect calculation).
You could use outer apply() like so:
select
erp_user.login
, [Invoices Billed] = sum(invoice_header.invoice_amount)
, x.[Open POs]
from erp_user
left join order_header
on erp_user.erp_user_id = order_header.req_by
left join invoice_instruct_header
on order_header.order_id = invoice_instruct_header.order_id
left join invoice_header
on invoice_instruct_header.instruct_id = invoice_header.instruct_no
outer apply (
select
[Open POs] = sum(po_header.po_amount)
from po_header p
inner join order_header oh
on oh.order_id = p.order_id
where oh.req_by = erp_user.erp_user_id
) x
where erp_user.supervisor_id is not null
and erp_user.company_id is not null
and erp_user.is_active = 1
and user_id_type = 'I'
group by erp_user.login

Joining two SQL statements in postgres

How would I join both of these statements together so it comes up as one? The two counts are being done separately as it is coming from two different tables.
SELECT ril.invoice_label_id, ril.invoice_label, ril.invoice_label_code,
fp.price as fee, count(*) as ct, l.link_id
FROM consultation_chl c
INNER JOIN link_service_pct_location l on l.link_id=c.link_id
INNER JOIN medication m ON c.consult_id=m.consult_id
INNER JOIN ref_invoice_label ril ON m.formulary_id = ril.formulary_id
INNER JOIN pharmacy ph ON ph.pharmacy_id = l.id AND l.location_type_id = 3
INNER JOIN formulary f ON f.formulary_id=m.formulary_id
INNER JOIN formulary_price fp ON fp.formulary_id=f.formulary_id
WHERE l.pct_id = 1425
AND l.service_id = 4
AND c.invoice_period = '2015-04-30'
AND ril.section_id=2
AND ril.invoice_label_code in ('MEDTABS','MEDCAPS','DOXYCAPS','DOXYTABS')
AND fp.valid_from <= c.consult_date
AND (fp.valid_to >= c.consult_date OR fp.valid_to IS NULL) GROUP BY ril.invoice_label_id, ril.invoice_label, ril.invoice_label_code,
fp.price, l.link_id
SELECT ril.invoice_label_id, ril.invoice_label, ril.invoice_label_code,
ricf.fee, count(*) as ct, l.link_id
FROM consultation_chl c
INNER JOIN link_service_pct_location l on l.link_id=c.link_id
INNER JOIN medication m ON c.consult_id=m.consult_id
INNER JOIN ref_invoice_label ril ON m.formulary_id = ril.formulary_id
INNER JOIN pharmacy ph ON ph.pharmacy_id = l.id AND l.location_type_id = 3
INNER JOIN formulary f ON f.formulary_id=m.formulary_id
INNER JOIN formulary_price fp ON fp.formulary_id=f.formulary_id
INNER JOIN ref_invoice_consult_fee ricf ON ricf.invoice_label_id = ril.invoice_label_id
WHERE l.pct_id = 1425
AND l.service_id = 4
AND c.invoice_period = '2015-04-30'
AND ril.section_id=2
AND ril.invoice_label_code in ('MEDSUSP15-25','MEDSUSP16-35','MEDSUSP26-35','MEDSUSP36-45','MEDSUSP45+')
AND fp.valid_from <= c.consult_date
AND (fp.valid_to >= c.consult_date OR fp.valid_to IS NULL) GROUP BY ril.invoice_label_id, ril.invoice_label, ril.invoice_label_code,
ricf.fee, l.link_id
You should take a look at the UNION operator.
SQL UNION Operator at W3schools.com
As your selected columns each have same names
you should be able to concatenate the selects with a "UNION" keyword in between.

Subquery in from clause, Invalid Identifier in Where clause

select * from iiasa_inventory.inv_device d
join iiasa_inventory.inv_type ty on d.type_id = ty.id
join iiasa_inventory.inv_category c on ty.category_id = c.id
join iiasa_inventory.inv_device_2_barcode b on b.device_id = d.id
join iiasa_inventory.inv_barcodes bc on b.barcode_id = bc.id
join iiasa_inventory.inv_status s on d.status = s.id
join iiasa_inventory.inv_brand br on ty.brand_id = br.id
left join iiasa_inventory.inv_supplier su on su.id = d.supplier_id
left join iiasa_inventory.inv_supplier sup on sup.id = d.maintenance_with
left join (select distinct device_id from
iiasa_inventory.inv_device_2_persons_cc) dp
on dp.device_id = d.id
where dp.active = 1
I am trying to select my data but the where-clause says that "dp.active" is an INVALID Identifier. This is probably because the table dp is in the subquery. I have tried to give it an alias name and some other things I found while browsing stackoverflow, but I cant seem to find a solution. Any idea?
This is Oracle PL/SQL.
Put the check for active = 1 in the subquery as shown below.
select * from iiasa_inventory.inv_device d
join iiasa_inventory.inv_type ty on d.type_id = ty.id
join iiasa_inventory.inv_category c on ty.category_id = c.id
join iiasa_inventory.inv_device_2_barcode b on b.device_id = d.id
join iiasa_inventory.inv_barcodes bc on b.barcode_id = bc.id
join iiasa_inventory.inv_status s on d.status = s.id
join iiasa_inventory.inv_brand br on ty.brand_id = br.id
left join iiasa_inventory.inv_supplier su on su.id = d.supplier_id
left join iiasa_inventory.inv_supplier sup on sup.id = d.maintenance_with
left join (select distinct device_id from iiasa_inventory.inv_device_2_persons_cc where active = 1) dp on dp.device_id = d.id
That is because you are not selecting active column in dp.
select * from iiasa_inventory.inv_device d
join iiasa_inventory.inv_type ty on d.type_id = ty.id
join iiasa_inventory.inv_category c on ty.category_id = c.id
join iiasa_inventory.inv_device_2_barcode b on b.device_id = d.id
join iiasa_inventory.inv_barcodes bc on b.barcode_id = bc.id
join iiasa_inventory.inv_status s on d.status = s.id
join iiasa_inventory.inv_brand br on ty.brand_id = br.id
left join iiasa_inventory.inv_supplier su on su.id = d.supplier_id
left join iiasa_inventory.inv_supplier sup on sup.id = d.maintenance_with
left join (select distinct device_id,active from iiasa_inventory.inv_device_2_persons_cc) dp on dp.device_id = d.id
where dp.active = 1
OR you can just filter from the subquery itself. Like:
left join (select distinct device_id
from iiasa_inventory.inv_device_2_persons_cc
where active=1) dp on dp.device_id = d.id

sql 2008 error 'the column prod_desc1 was specified multiple times for "a"'

I've got this ginormous sql select statement I'm using in a SSRS 2008 report. I need field "prod_desc1" from the Product table, but also the same named field from Order_Line. I've aliased both of them but I'm still getting the error. Here's my statment:
SELECT order_num, quote_num, cust_num, cust_desc, ship_via_desc, whse_desc, slsm_desc, ar_term_desc, vend_desc, pline_desc, major_grp, cust_po_num, ord_date, req_date, shp_date, ord_type, tot_ord_$, pline_num, prod_num, price_ext, STATUS, prod_desc1 as prod_desc, prod_desc1 as com1, prod_desc2 as com2, net_price, seq_num
FROM (SELECT o.order_num, o.quote_num, o.cust_num, c.cust_desc, s.ship_via_desc, w.whse_desc, sa.slsm_desc, t.ar_term_desc, v.vend_desc, ca.pline_desc, ca.major_grp, o.cust_po_num, o.ord_date, o.req_date, o.shp_date, o.ord_type, o.tot_ord_$, ol. pline_num, ol.prod_num, price_ext, 'Open' AS STATUS, p.prod_desc1, ol.prod_desc1, ol.prod_desc2, ol.net_price, seq_num
FROM [ORDER] o
left outer join order_line ol on o.order_num = ol.order_num
left outer join product p on ol.prod_num = p.prod_num
left outer join customer c on o.cust_num = c.cust_no
left outer join ship_via s on o.ship_via_num = s.ship_via_id
left outer join whse_addr w on o.shp_whse = w.whse_num
left outer join salesman sa on o.slsm2_num = sa.slsm_num
left outer join terms t on o.ar_term_num = t.ar_term_num
left outer join vend v on ol.prim_vend_num = v.vend_num
left outer join category ca on ol.pline_Num = ca.pline_Id
WHERE (#OrderNum is null OR o.order_num = (#OrderNum)) and
o.cust_num IN (#CustomerNumber) and
(ol.prim_vend_num IN (#VendNum) or ol.prim_vend_num is NULL) and
o.req_date between (#ReqDateFrom) and (#ReqDateTo) and
o.ord_date between (#EntDateFrom) and (#EntDateTo) and
(c.slsm_num = (#SlsmnRealNum) and ol.major_grp IN ('C', 'R', 'W') or c.slsm2_num = (#SlsmnRealNum) and ol.major_grp IN ('P', 'S')) and
ol.major_grp IN (#MajorGrp) and
ol.pline_num IN (#ProductLine) and
(#PONum is null OR o.cust_po_num LIKE ('%' + #PONum + '%')) and
(#ItemNum is null OR ol.prod_num = (#ItemNum))
UNION ALL
SELECT o.order_num, o.quote_num, o.cust_num, c.cust_desc, s.ship_via_desc, w.whse_desc, sa.slsm_desc, t.ar_term_desc, v.vend_desc, ca.pline_desc, ca.major_grp, o.cust_po_num, o.ord_date, o.req_date, o.shp_date, o.ord_type, o.tot_ord_$, ol.pline_num, ol.prod_num, net_ext, 'Closed' AS STATUS, p.prod_desc1, ol.prod_desc1, ol.prod_desc2, ol.net_price, seq_num
FROM ORDER_HISTORY o
left outer join order_history_line ol on o.order_num = ol.order_num
left outer join product p on ol.prod_num = p.prod_num
left outer join customer c on o.cust_num = c.cust_no
left outer join ship_via s on o.ship_via_num = s.ship_via_id
left outer join whse_addr w on o.shp_whse = w.whse_num
left outer join salesman sa on o.slsm2_num = sa.slsm_num
left outer join terms t on o.ar_term_num = t.ar_term_num
left outer join vend v on ol.prim_vend_num = v.vend_num
left outer join category ca on ol.pline_Num = ca.pline_Id
WHERE (#OrderNum is null OR o.order_num = (#OrderNum)) and
o.cust_num IN (#CustomerNumber) and
(ol.prim_vend_num IN (#VendNum) or ol.prim_vend_num is NULL) and
o.req_date between (#ReqDateFrom) and (#ReqDateTo) and
o.ord_date between (#EntDateFrom) and (#EntDateTo) and
(c.slsm_num = (#SlsmnRealNum) and ol.major_grp IN ('C', 'R', 'W') or c.slsm2_num = (#SlsmnRealNum) and ol.major_grp IN ('P', 'S')) and
ol.major_grp IN (#MajorGrp) and
ol.pline_num IN (#ProductLine) and
(#PONum is null OR o.cust_po_num LIKE ('%' + #PONum + '%')) and
(#ItemNum is null OR ol.prod_num = (#ItemNum))) as a
WHERE (STATUS = CASE WHEN #OrderType = 'Both' THEN STATUS ELSE #OrderType END) ORDER BY cust_desc, req_date, vend_desc
any help would be greatly appreciated! :)

Conditional INNER JOIN in SQL Server

I have a rather complex query that pretty much mimics a test query I have below:
SELECT C.*
FROM Customer C
INNER JOIN CustDetail CD ON C.CustomerId = CD.CustomerId
INNER JOIN Address A ON CD.DetailID = A.DetailID
INNER JOIN Group G ON C.CustomerId = G.CustomerId --Join only when C.code = 1
INNER JOIN GroupDetail D ON G.GroupId = D.DetailId --Join only when C.code = 1
WHERE G.Active = 1 AND --Only when C.code = 1
D.code = '1' AND --Only when C.code = 1
C.Id = #customerId
I'd like to do INNER JOINs on Group G and GroupDetail D (and ofcourse not have them in the WHERE conditions based on the table column C.code = 1
I replaced the INNER JOINs with LEFT OUTER JOINs for both the join conditions, but the result set is not what was expected
How do I conditionally do the JOIN
SELECT C.*
FROM Customer C
INNER JOIN CustDetail CD ON C.CustomerId = CD.CustomerId
INNER JOIN Address A ON CD.DetailID = A.DetailID
LEFT OUTER JOIN Group G ON C.CustomerId = G.CustomerId
LEFT OUTER JOIN GroupDetail D ON G.GroupId = D.DetailId
WHERE ((G.Active = 1 AND C.code = 1) OR G.Active IS NULL) AND
((D.code = '1' AND C.code = 1) OR D.code IS NULL) AND
C.Id = #customerId
I'm guessing you didn't include the IS NULL checks before so you never got to see rows where C.code <> 1 ?
You should check for NULL on a field that will never be null. This is almost always 'id', but it's not clear that you have a G.id or a D.id.
I'm guessing what you want is just a tighter ON clause, and a compound condition.
SELECT C.*
FROM Customer C
INNER JOIN CustDetail CD ON C.CustomerId = CD.CustomerId
INNER JOIN Address A ON CD.DetailID = A.DetailID
-- the next two joins happen only when c.code=1
-- their columns will be null when there is no match.
LEFT JOIN Group G ON C.CustomerId = G.CustomerId AND C.Code = 1
LEFT JOIN GroupDetail D ON G.GroupId = D.DetailId AND C.Code = 1
WHERE C.Id = #customerId AND --always check this
-- this condition is true if code is null or code isn't 1,
((C.code IS NULL or C.code <> 1)
-- or (if the code is 1), it is true if g.active and d.code
OR (G.Active = 1 AND D.code = '1'))
This will do a semi-join only when code is 1.
SELECT C.*
FROM Customer C
INNER JOIN CustDetail CD
ON C.CustomerId = CD.CustomerId
INNER JOIN Address A
ON CD.DetailID = A.DetailID
WHERE
C.Id = #customerId AND
(c.code != 1 OR
EXISTS(
SELECT NULL
FROM Group G
JOIN GroupDetail D ON G.GroupId = D.DetailId
WHERE
C.CustomerId = G.CustomerId AND
G.Active = 1 AND
D.code = '1'
))