Odd 'GROUP BY' error in a sub-query while using Oracle - sql

A quick background -- I need to find the termination rates of cases that go through our company lab grouped by case type and month. So far I came up with this:
SELECT BPI.TYPE,
EXTRACT(MONTH FROM CS.RECEIVED_DATE) MONTH,
COUNT(*) termed_cases
FROM CELL_SOURCE cs
JOIN BASIC_PATHOLOGY_INFO bpi ON CS.CELL_SOURCE_ID = BPI.CELL_SOURCE_ID
JOIN RECENT_CELL_SOURCE_STATUS rcss ON CS.CELL_SOURCE_ID = RCSS.CELL_SOURCE_ID
WHERE type IS NOT NULL
AND CS.RECEIVED_DATE > to_date('03/01/2011', 'MM/DD/YYYY/')
AND RCSS.STATUS like 'Term%'
GROUP BY BPI.TYPE, EXTRACT(MONTH FROM CS.RECEIVED_DATE)
ORDER BY month, type
This finds all cases that have been termed, easy enough. However, when I want to find the rate, I get a bit of a problem. I tried using a sub-query to catch the total amount of cases per type regardless of it's status, as such:
COUNT(*)/(SELECT COUNT(*)
FROM CELL_SOURCE cs_1
JOIN BASIC_PATHOLOGY_INFO bpi_1 ON CS_1.CELL_SOURCE_ID = BPI_1.CELL_SOURCE_ID
WHERE BPI_1.TYPE = BPI.TYPE
AND EXTRACT(month from CS_1.RECEIVED_DATE) = EXTRACT(MONTH FROM CS.RECEIVED_DATE)) termed_cases
However, this throws an ORA-00979: not a GROUP BY expression error, and highlights BPI.TYPE from the sub-query.
Anyone have any idea what my error could actually be? Also, would an analytical function work better here than an aggregate function?

So, you need two counts: a total for all cases in the month and a total for just the Termed cases. The easiest way of doing this is to use a CASE() function to execute a conditional count, like this:
SELECT BPI.TYPE,
EXTRACT(MONTH FROM CS.RECEIVED_DATE) MONTH,
COUNT(*) all_cases,
sum(case when RCSS.STATUS like 'Term%' then 1 else 0 end ) termed_cases
FROM CELL_SOURCE cs
JOIN BASIC_PATHOLOGY_INFO bpi ON CS.CELL_SOURCE_ID = BPI.CELL_SOURCE_ID
JOIN RECENT_CELL_SOURCE_STATUS rcss ON CS.CELL_SOURCE_ID = RCSS.CELL_SOURCE_ID
WHERE tumor_type IS NOT NULL
AND CS.RECEIVED_DATE > to_date('03/01/2011', 'MM/DD/YYYY/')
GROUP BY BPI.TUMOR_TYPE, EXTRACT(MONTH FROM CS.RECEIVED_DATE)
ORDER BY month, tumor_type
Note that I have removed the LIKE filter from the WHERE clause.

select bpi.type , month,
termed_cases /
(select count(*)
from CELL_SOURCE cs_1
inner join BASIC_PATHOLOGY_INFO bpi_1
on CS_1.CELL_SOURCE_ID = BPI_1.CELL_SOURCE_ID
where BPI_1.TUMOR_TYPE = BPI.TUMOR_TYPE
and extract(month from CS_1.RECEIVED_DATE) = extract(MONTH FROM CS.RECEIVED_DATE)
)
from (
select BPI.TYPE,
extract(MONTH FROM CS.RECEIVED_DATE) MONTH,
count(*) termed_cases
from CELL_SOURCE cs
inner join BASIC_PATHOLOGY_INFO bpi
on CS.CELL_SOURCE_ID = BPI.CELL_SOURCE_ID
inner join RECENT_CELL_SOURCE_STATUS rcss
on CS.CELL_SOURCE_ID = RCSS.CELL_SOURCE_ID
where tumor_type is not null
and CS.RECEIVED_DATE > to_date('03/01/2011', 'MM/DD/YYYY/')
and RCSS.STATUS like 'Term%'
group by BPI.TYPE, extract(MONTH FROM CS.RECEIVED_DATE)
)
order by month, type

Related

Joining two queries together into one main table

I have the following two queries that I need to join together to get one final output.
The primary keys are year, month,cost_center, g.account, and e.submapping.
The first table is an acutals table from a GL while the second query is a planned amount. I am trying to compare actuals to plan and need to join these two tables with the primary keys listed.
---Query 1 (e)
with Ranking as (
select c.*, rank() over(partition by
c.ledger_name,
c.company_code,
c.location_code,
c.cost_center,
c.account_number,
c.period_name,
c.currency,
c.amount,
c.entered_amount,
c.dm_insert_dt
order by dw_last_updated DESC) rnk
from wbr_global.gl_ap_details c
where cost_center IN ('1168','1153','1172','1257')
and ledger_name IN ('ABC.com, Inc.')
and account_number between '59999' and '70000')
select
to_date(period_name, 'Mon-YY') as BalanceDate,
date_part(month,(to_date(period_name, 'Mon-YY'))) as Months,
Case
when right(period_name,2) = right(date_part_year(current_date),2) then 'Current Year'
when right(period_name,2) = right(date_part_year(current_date) - 1,2) then 'Prior Year'
else 'Error' end as YearFlag,
EXTRACT(YEAR from balancedate) as year,
EXTRACT(Month from balancedate) as month,
e.sub_mapping,
c.cost_center,
c.period_name,
sum(c.amount) as amount
from Ranking c
left join wbr_global.raw_station_extended_attribute d on c.location_code = d.location_code
left join sandbox.utr_fixed_mapping_na e on c.account_number = e.account_number
where c.cost_center IN ('1168','1153','1172','1257')
and c.ledger_name = 'abc.com, Inc.'
and c.rnk = 1
group by 1,2,3,4,5,6,7,8
limit 10
Here is the second query
---Second query g
EXTRACT(YEAR from first_day_of_month) as year,
EXTRACT(Month from first_day_of_month) as month,
first_day_of_month,country,cost_center,scenario,'employee_relation' as account,
sum(employee_relation) as amount
from prophecy_to_sabre_ds_db.prophecy_caffeine.output_ww_field_opex
where cost_center = 1172
AND scenario = 'Q2G_22_1'
group by 1,2,3,4,5,6
Would I be able to make one a sub query in the other and join that way.
(Query 2) as g on g.cost_center = c.cost_center
and g.account = e.sub_mapping
and g.year = e.year
and g.month = e.month

ERROR: missing FROM-clause entry for table "p"

I am trying to use a UNION to append the total column in the first top half to the second half of the query.
SELECT NULL as month, NULL as active, count(cage_player_id) as total
FROM player_signup as p
GROUP BY date_part('month', p.signup_date)
UNION
SELECT date_part('month', signup_date) as month, count(DISTINCT(p.cage_player_id)) as active, NULL as total
FROM player_signup as p
JOIN daily_kpis as d ON p.cage_player_id = d.cage_player_id
WHERE slot_bet_amount > 0
OR ld_bet_amount > 0
OR table_bet_amount > 0
GROUP BY date_part('month', p.signup_date)
ORDER BY date_part('month', p.signup_date) ASC
I keep getting an error that says the FROM clause is missing for table p. Can anyone help? Is there an easier way to combine these two queries?
Here is what each query looks like separately. I just want to add the total column right next to the month and active column. The total ID's would still be broken down by months.
Query 1
Query 2
The problem is the order by clause. It applies to the results of the union query, so it cannot see the identifiers that are defined within the queries. Instead, you should use the names of the column in the resultset.
So you want to change this:
ORDER BY date_part('month', p.signup_date) ASC
To:
ORDER BY month
I believe this is the query you need:
SELECT date_part('month', signup_date) as month
, count(DISTINCT(p.cage_player_id)) as active
, (select count(cage_player_id)
FROM player_signup as p
GROUP BY date_part('month', p.signup_date)) as total
FROM player_signup as p
JOIN daily_kpis as d ON p.cage_player_id = d.cage_player_id
WHERE slot_bet_amount > 0
OR ld_bet_amount > 0
OR table_bet_amount > 0
GROUP BY date_part('month', p.signup_date)
ORDER BY date_part('month', p.signup_date) asc
I am not so good at Postgresql, please try this:
SELECT date_part('month', signup_date) as month
, count(DISTINCT(p.cage_player_id)) as active
, max(t1.total) as total
FROM player_signup as p
left join (select count(pp.cage_player_id) over (partition by date_part('month', pp.signup_date)) as total
, date_part('month', pp.signup_date) date_p
FROM player_signup as pp) t1 on t1.date_p = date_part('month', p.signup_date)
JOIN daily_kpis as d ON p.cage_player_id = d.cage_player_id
WHERE slot_bet_amount > 0
OR ld_bet_amount > 0
OR table_bet_amount > 0
GROUP BY date_part('month', p.signup_date)
ORDER BY date_part('month', p.signup_date)

Date field not contained in either an aggregate function or the GROUP BY clause

I am trying to calculate "Month to date" using three joined tables. It always gives me error "not contained in either an aggregate function or the GROUP BY clause" The date field is S.BUS_DAT
I tried many things but always get same error. Any advise
Here is the code I use
SELECT
-- Select from IM_IN
M.ITEM_NO,
M.DESCR,
N.QTY_ON_HND,
M.PRC_1,
N.LST_COST,
N.LST_RECV_DAT,
--Select from IM_ITEM
M.CATEG_COD,
M.ATTR_COD_1,
M.ITEM_VEND_NO,
M.ALT_1_UNIT,
M.ALT_1_NUMER,
M.LST_COST,
count (S.BUS_DAT) AS BUS_DAYS,
**sum (QTY_SOLD) OVER (PARTITION BY Month (S.BUS_DAT))as **MTD****
FROM
dbo.IM_INV N
INNER JOIN dbo.IM_ITEM M
ON
N.ITEM_NO = M.ITEM_NO
INNER JOIN
dbo.PS_TKT_HIST_LIN S
ON
N.ITEM_NO = S.ITEM_NO
Group by
M.ITEM_NO,
M.DESCR,
M.ITEM_VEND_NO,
M.CATEG_COD,
M.ATTR_COD_1,
N.QTY_ON_HND,
N.LST_COST,
N.LST_RECV_DAT,
N.LST_SAL_DAT,
M.ALT_1_UNIT,
M.ALT_1_NUMER,
M.PRC_1,
M.LST_COST
Order by M.ITEM_NO
try to include Month(S.BUS_DAT) into group by as well:
SELECT
M.ITEM_NO,
M.DESCR,
N.QTY_ON_HND,
M.PRC_1,
N.LST_COST,
N.LST_RECV_DAT,
M.CATEG_COD,
M.ATTR_COD_1,
M.ITEM_VEND_NO,
M.ALT_1_UNIT,
M.ALT_1_NUMER,
M.LST_COST,
COUNT(S.BUS_DAT) AS BUS_DAYS,
SUM(QTY_SOLD) OVER(PARTITION BY MONTH(S.BUS_DAT)) AS MTD
FROM dbo.IM_INV N
INNER JOIN dbo.IM_ITEM M ON N.ITEM_NO = M.ITEM_NO
INNER JOIN dbo.PS_TKT_HIST_LIN S ON N.ITEM_NO = S.ITEM_NO
GROUP BY M.ITEM_NO,
M.DESCR,
M.ITEM_VEND_NO,
M.CATEG_COD,
M.ATTR_COD_1,
N.QTY_ON_HND,
N.LST_COST,
N.LST_RECV_DAT,
N.LST_SAL_DAT,
M.ALT_1_UNIT,
M.ALT_1_NUMER,
M.PRC_1,
M.LST_COST,
MONTH(S.BUS_DAT)
ORDER BY M.ITEM_NO;
I believe you want:
sum(sum(QTY_SOLD)) OVER (PARTITION BY Month(S.BUS_DAT)) as MTD
Note: You will still need month(s.bus_dat) in the group by clause.
If you only want the sum for the current month, then you don't want a window function, just conditional aggregation:
sum(case when year(s.bus_dat) = year(getdate()) and month(s.bus_dat) = month(getdate())
then qty_sold
end) as mtd

Select count inner join two database

I want to show all supplier information sorted by country, including number of names supplied in current month.
Here are the two database and their variables:
1.Supplier: SupplierID, Suppliedname, Country, ReliabilityScore, ContactInfo
2.SuppliedName: SnID, Suppliedname1, Language, Status, Standard, PlaceID,SupplierID, Supplieddate
Here's what I came up with which didn't really work:
SELECT COUNT(DISTINCT SuppliedName.suppliedname1), Supplier.(*) FROM SuppliedName
INNER JOIN Supplier ON Supplier.SupplierID = SuppliedName.SupplierID
WHERE EXTRACT(MONTH FROM SuppliedName.Supplieddate)=EXTRACT(MONTH FROM sysdate) AND EXTRACT(YEAR FROM SuppliedName.Supplieddate)=EXTRACT(YEAR FROM sysdate)
ORDER BY Supplier.Country;
Please help!!! Thanks!
I guess you just missed to GROUP BY all columns from SUPPLIER.
SELECT COUNT(DISTINCT SUPPLIEDNAME.SUPPLIEDNAME1),
SUPPLIER.SUPPLIERID,
SUPPLIER.SUPPLIEDNAME,
SUPPLIER.COUNTRY,
SUPPLIER.RELIABILITYSCORE,
SUPPLIER.CONTACTINFO
FROM SUPPLIEDNAME
INNER JOIN SUPPLIER
ON SUPPLIER.SUPPLIERID = SUPPLIEDNAME.SUPPLIERID
WHERE EXTRACT(MONTH FROM SUPPLIEDNAME.SUPPLIEDDATE) = EXTRACT(MONTH FROM SYSDATE)
AND EXTRACT(YEAR FROM SUPPLIEDNAME.SUPPLIEDDATE) = EXTRACT(YEAR FROM SYSDATE)
GROUP BY SUPPLIER.SUPPLIERID,
SUPPLIER.SUPPLIEDNAME,
SUPPLIER.COUNTRY,
SUPPLIER.RELIABILITYSCORE,
SUPPLIER.CONTACTINFO
ORDER BY SUPPLIER.COUNTRY;

Joining multiple sum sql statements

How can I join multiple sql statements. I need to display in one view respectively 2004,2008,2009 and so on
SELECT SUM(ACQUISITIONPRICE) AS YEAR_2007
FROM TRANS
WHERE DATEACQUIRED LIKE '%07';
SELECT SUM(ACQUISITIONPRICE) AS YEAR_2008
FROM TRANS
WHERE DATEACQUIRED LIKE '%08';
SELECT SUM(ACQUISITIONPRICE) AS YEAR_2009
FROM TRANS
WHERE DATEACQUIRED LIKE '%09';
check this sql fiddle
I have handled your requirement with case statement which seems to be very easy.
SELECT SUM(ACQUISITIONPRICE) AS TOTALPRICE
, EXTRACT(year from DATEACQUIRED) AS YEAR
FROM TRANS
GROUP BY EXTRACT(year from DATEACQUIRED)
ORDER BY YEAR;
SELECT Sum(CASE
WHEN Extract(year FROM dateacquired) = 2007 THEN acquisitionprice
ELSE 0
END) AS YEAR_2007,
Sum(CASE
WHEN Extract(year FROM dateacquired) = 2008 THEN acquisitionprice
ELSE 0
END) AS YEAR_2008,
Sum(CASE
WHEN Extract(year FROM dateacquired) = 2009 THEN acquisitionprice
ELSE 0
END) AS YEAR_2009
FROM trans
Just use GROUP BY like so:
SELECT SUM(ACQUISITIONPRICE) AS TOTALPRICE
, EXTRACT(year from DATEACQUIRED) AS YEAR
FROM TRANS
GROUP BY EXTRACT(year from DATEACQUIRED)
ORDER BY YEAR
If you really want to "join" them all in one row, with specific column names, you can do the following (though this approach is less flexible, since the query will have to be manually modified every year). Also note that although the question specifically mentioned "joining" the results, the join as shown below is completely unnecessary. Each column could simply be part of the select clause without any join. (here is the SqlFiddle)
SELECT * FROM
(SELECT SUM(ACQUISITIONPRICE) AS YEAR_2007
FROM TRANS
WHERE EXTRACT(year from DATEACQUIRED) = 2007) a
JOIN
(SELECT SUM(ACQUISITIONPRICE) AS YEAR_2008
FROM TRANS
WHERE EXTRACT(year from DATEACQUIRED) = 2008) b ON 1=1
JOIN
(SELECT SUM(ACQUISITIONPRICE) AS YEAR_2009
FROM TRANS
WHERE EXTRACT(year from DATEACQUIRED) = 2009) c ON 1=1
If you want the results in a single row, a preferable approach is to use a sub-select with dual as shown in this fiddle:
SELECT
(SELECT SUM(ACQUISITIONPRICE) FROM TRANS WHERE EXTRACT(year from DATEACQUIRED) = 2007) AS YEAR_2007
, (SELECT SUM(ACQUISITIONPRICE) FROM TRANS WHERE EXTRACT(year from DATEACQUIRED) = 2008) AS YEAR_2008
, (SELECT SUM(ACQUISITIONPRICE) FROM TRANS WHERE EXTRACT(year from DATEACQUIRED) = 2009) AS YEAR_2009
FROM dual
When it comes to performance, the only real way to be sure is of course to test it in your particular scenario, but the SUM (CASE... approach shown by #Indra-Prakash-Tiwari may perform better in most cases (if oracle behaves anything like sql server)
Try Use To_Char
Fiddle demo
select TO_CHAR(DATEACQUIRED,'yy') AS Years_Char,Sum(ACQUISITIONPRICE)
FROM trans GROUP BY TO_CHAR(DATEACQUIRED,'yy')