ORA-00937: not a single-group group function for sum function - sql

I am trying to sum up the COUNT(IHID.RSID_PROD_N) by IHID.CS_ID but facing a problem. How to solve it?
SELECT
IHID.CS_ID ,IHID.RSID_PROD_N,COUNT(IHID.RSID_PROD_N),
RSPF.RSPF_PROD_N,COUNT(RSPF.RSPF_PROD_N),sum(COUNT(IHID.RSID_PROD_N))
from IHIH
JOIN IHID
ON ihih.rsih_invoice_n = ihid.rsih_invoice_n AND ihih.cs_id = ihid.cs_id
JOIN RSPF
ON ihih.cs_id = rspf.cs_id AND ihid.rsid_prod_n=rspf.rspf_prod_n
WHERE rspf_desc LIKE '%SCISSOR LIFT'
GROUP BY IHID.CS_ID, IHID.RSID_PROD_N,RSPF.RSPF_PROD_N,IHID.CS_ID;
The table is something like this
16 SJIII4626 1 SJIII4626 1
16 SJIII4632 1 SJIII4632 1
I want 1+1=2 for 16

I think you need analytic functions rather than aggregates here. Something like:
SELECT
IHID.CS_ID
,IHID.RSID_PROD_N
,row_number() over (partition by IHID.CS_ID order by IHID.RSID_PROD_N) as IHID_RSID_PROD_N
,RSPF.RSPF_PROD_N
,row_number() over (partition by IHID.CS_ID order by RSPF.RSPF_PROD_N) as RSPF_RSPF_PROD_N
,COUNT(IHID.RSID_PROD_N) over (partition by IHID.CS_ID) as sum_count
from IHIH
JOIN IHID
ON ihih.rsih_invoice_n = ihid.rsih_invoice_n AND ihih.cs_id = ihid.cs_id
JOIN RSPF
ON ihih.cs_id = rspf.cs_id AND ihid.rsid_prod_n=rspf.rspf_prod_n
WHERE rspf_desc LIKE '%SCISSOR LIFT'
;
Not entirely sure because your question lacks a complete test case.
If this answer isn't quite what you want please edit your question to provide table structures and sample input data together with required output derived from that data.

Its not grouping as you would like because of the unique values in IHID.RSID_PROD_N and RSPF.RSPF_PROD_N. Remove those columns and it will group as expected.

One option is to use your current query (almost unchanged) as a CTE, and then apply SUM to a COUNT which you couldn't have done in a nested manner. Something like this:
with your_current_query as
-- removed nested SUM(COUNT)
(select
ihid.cs_id,
ihid.rsid_prod_n,
rspf.rspf_prod_n,
count(ihid.rsid_prod_n) cnt_rsid
count(rspf.rspf_prod_n) cnt_rspf
from ihih join ihid on ihih.rsih_invoice_n = ihid.rsih_invoice_n
and ihih.cs_id = ihid.cs_id
join rspf on ihih.cs_id = rspf.cs_id
and ihid.rsid_prod_n=rspf.rspf_prod_n
where rspf_desc like '%SCISSOR LIFT'
group by ihid.cs_id,
ihid.rsid_prod_n,
rspf.rspf_prod_n
)
select cs_id,
rsid_prod_n,
rspf_prod_n,
cnt_rsid,
cnt_rspf,
sum(cnt_rsid) sum_cnt_rsid --> this represents nested SUM(COUNT)
from your_current_query
group by cs_id,
rsid_prod_n,
rspf_prod_n,
cnt_rsid,
cnt_rspf;

Related

Using the results of one SQL query in another query (Athena)

I'm a bit stuck on how can do this so hoping someone can point me in the right direction.
I have this simple query:
SELECT acchl.is_current,
acchl.aircraft_registration_number,
acchl.aircraft_transponder_code
FROM fleets.aircraft_all_history_latest acchl
WHERE acchl.is_current = true
Which I then want to use the results from this query to find all the duplicate aircraft transponder codes along with the aircraft registration numbers with something like a self join to fetch the actual rows that may have duplicate values using something like this:
select s.id, s.col_maybe_dups
from sometab s
join (select col_maybe_dups as cd
from sometab
group by cd
having count(*) > 1) x
on x.cd = s.col_maybe_dups;
Looks good!
You could WITH it too...
WITH data as (
SELECT acchl.is_current,
acchl.aircraft_registration_number,
acchl.aircraft_transponder_code
FROM fleets.aircraft_all_history_latest acchl
WHERE acchl.is_current
)
select * from data
where aircraft_transponder_code in
(select aircraft_transponder_code
from data
group by 1
having count(*) > 1
)

What is the equivalent of SQL's WITHIN GROUP in BigQuery?

I am trying to convert a stored procedure which is written in T-SQL to BigQuery compatible syntax.
In one of the temp table used inside the proc, there is a function WITHIN GROUP as given in the query below.
SELECT DISTINCT
flr_id, lid, sentinel, liquid, d_id, sent_time, tracker,
(PERCENTILE_CONT(0.5) WITHIN GROUP (ORDER BY ((DATE_DIFF(second, (sent_time), (tracker))/3600.0)) ASC) OVER (PARTITION BY flr_id, sentinel, d_id)/24.0) AS mct
FROM
history AS h
INNER JOIN
magent AS mag ON mag.flat = h.flat
INNER JOIN
stepand AS stepand ON stepand.soid = h.soid
INNER JOIN
sv AS st_v ON st_v.stoid = stepand.stoid
INNER JOIN
tvr AS tvr ON tvr.trvid = stepand.trvid
INNER JOIN
sdv AS sdv ON st_v.stoid = sdv.stoid
WHERE
liquid > 0
AND mag.flr_id = '1234'
AND tracker <= GETDATE()
AND sent_time >= DATEADD(WEEK, 1, GETDATE())
AND d_id NOT LIKE ('UNKNOWN')
AND part_type_code NOT IN ('ABCDE')
AND h.lid not like 'B%'
AND h.lid not like 'T%'
AND h.lid not like 'VL%'
AND h.step_deleted_sw <> 'Y'
AND h.lid NOT IN (SELECT lid from test)");
I converted all of the query except for this line.
(PERCENTILE_CONT(0.5) WITHIN GROUP (ORDER BY ((DATE_DIFF(second,
(sent_time), (tracker))/3600.0)) ASC) OVER (PARTITION BY flr_id,
sentinel, d_id)/24.0) AS mct
I looked for WITHIN GROUP in SQL and found a good explanation here
What I don't understand is what is the equivalent function for WITHIN GROUP on Bigquery ?
When I tried to run the query as it is, I get an error
Syntax error: Expected end of input but got keyword WITHIN at <PROCNAME>
Could anyone let me know how can I modify the line using WITHIN GROUP to big query compatible syntax ?
Ant help is much appreciated.
If I understand what you want to do, BigQuery implements this using the ORDER BY for the window function:
PERCENTILE_CONT(0.5) OVER (PARTITION BY flr_id, sentinel, d_id)/24.0
ORDER BY ((DATE_DIFF(second, (sent_time), (tracker))/3600.0)) ASC
) AS mct
Of course the DATE_DIFF() syntax is not correct for BigQuery and your query may have other issues as well. However, this answers the question that you specifically asked.

How to get top n rows from a dense_rank()

I'm trying to get collect the top customers from each region however I seem to run into the issue of not being able to specify that I want only the top customers.
I keep getting this error: ORA-00904: "RANK_UNITPRICE": invalid identifier and I know its coming from the where statement but I don't know how else to filter to get my expected output.
Here's what my code looks like:
select reg_name, cus_lname, sum(sale_units * sale_price) as total_sold,
rank() over (partition by reg_name order by sum(sale_units * sale_price) desc) as rank_unitprice
from dwregion
inner join dwcustomer on dwregion.reg_id = dwcustomer.reg_id
inner join dwsalesfact on dwcustomer.cus_code = dwsalesfact.cus_code
where rank_unitprice = 1
group by reg_name, cus_lname
It works if I take the where statement out the code works fine as expected (correct ranks and correct values) but its unfiltered (obviously).
How would I go about fixing this issue?
I'm using Oracle live and you can find the script here if it helps.
At first I didn't understand what something that you should do ("take the where clause out of code") doesn't work. Then I realized that you probably did it wrong - "out" here means that current query should be a subquery (or a CTE). Something like this:
WITH
temp
AS
( SELECT reg_name,
cus_lname,
SUM (sale_units * sale_price) AS total_sold,
RANK ()
OVER (PARTITION BY reg_name
ORDER BY SUM (sale_units * sale_price) DESC) AS rank_unitprice
FROM dwregion
INNER JOIN dwcustomer ON dwregion.reg_id = dwcustomer.reg_id
INNER JOIN dwsalesfact
ON dwcustomer.cus_code = dwsalesfact.cus_code
GROUP BY reg_name, cus_lname)
SELECT t.*
FROM temp
WHERE t.rank_unitprice = 1

SQL Grouping even and odd

I have to Group Certain data as so that it comes in 2 sets.
Attached image has details of actal data, expected result and data from query I used.
I am sure i am missing something in group by of max option .Please help
select agrmnt_id ,location_name, slab_no,target_start,target_end, tier_perc ,mod(RANK, 2) col from
(select agrmnt_id ,location_name, slab_no, target as target_start ,LAG(target) OVER (PARTITION BY location_name ORDER BY slab_no DESC)-1 as target_end ,PAY_PREC|| '%' as tier_perc,
DENSE_RANK() over(partition by agrmnt_id order by location_name) RANK
from plb_addnl_slab_details
where agrmnt_id='PLBCAI140262' order by location_name,slab_no
)) group by agrmnt_id,location_name ,slab_no
order by location_name1 ,slab_no1, location_name2 ,slab_no2
If I understand what you want, which is more than a little doubtful, it seems like you are able to generate a list of all the values you want, but you can't get them aligned in two sets? If so I think you need to treat your initial list as a base view and left outer join it to itself, using your col value to decide which is in first set and which in the second.
The criteria for joining seem a bit vague. If I add another ranking to stop the same values appearing twice in the second columns, I can get your expected result with this:
with t as (
select agrmnt_id, location_name, slab_no, target_start, target_end,
tier_perc , mod(col_rnk, 2) col, rnk
from (
select agrmnt_id, location_name, slab_no, target as target_start,
LAG(target) OVER (PARTITION BY location_name
ORDER BY slab_no DESC)-1 as target_end,
SLAB_PERC|| '%' as tier_perc,
DENSE_RANK() over(partition by agrmnt_id order by location_name) col_rnk,
RANK() over(partition by agrmnt_id, slab_no order by location_name) rnk
from plb_addnl_slab_details
where agrmnt_id='PLBCAI140262'
)
)
select t1.agrmnt_id as agrmnt_id_1, t1.location_name as location_name_1,
t1.slab_no as slab_no_1, t1.target_start as target_start_1,
t1.target_end as target_end_1,
t2.agrmnt_id as agrmnt_id_2, t2.location_name as location_name_2,
t2.slab_no as slab_no_2, t2.target_start as target_start_2,
t2.target_end as target_end_2
from t t1
left join t t2 on t2.agrmnt_id = t1.agrmnt_id
and t2.slab_no = t1.slab_no
and t2.rnk = t1.rnk + 1
and t2.col = 0
where t1.col = 1
order by t1.agrmnt_id, t1.location_name, t1.slab_no;
SQL Fiddle. I'm not convinced those join conditions (or the new rank) are quite right but can't really tell without more data, or more information about the logic you want to use. Hopefully this gives you something you can adapt though.

Why is this error coming Postgres

I have a following query
select wbod.subject, wbi.object,
age(dod.object,wbod.object) as ageOfPerson
from wasbornin as wbi,
wasbornondate as wbod,
diedondate as dod
where wbi.subject=wbod.subject
and wbod.subject=dod.subject
and age(dod.object,wbod.object) = (select max(age(dod1.object,wbod1.object))
from wasbornin as wbi1,
wasbornondate as wbod1,
diedondate as dod1
where wbi1.subject = wbod1.subject
and wbod1.subject=dod1.subject
group by wbi1.object)
group by wbi.object
ORDER BY wbi.subject;
But it is giving following error
column "wbod.subject" must appear in the GROUP BY clause or be used in an aggregate function
LINE 1: select wbod.subject, wbi.object
Why is this error coming
That's because you are selecting this column. And if given group (GROUP BY wbi.object) there are 150 different subjects, which one of them should be returned?
I initially misread the query - order is using wbi.subject, but error is about wbod.subject.
If I understand your query correctly, you actually don't need the sub-query or the group by:
select subject,
object,
ageOfPerson
from (
select wbod.subject,
wbi.object,
age(dod.object, wbod.object) as ageOfPerson,
dense_rank() over (partition by dod.subject order by age(dod.object, wbod.object) desc) as rnk
from wasbornin as wbi
join wasbornondate as wbod on wbi.subject=wbod.subject
join diedondate as dod on wbod.subject=dod.subject
) t
where rnk = 1;