hi kindly refer to the shared requirement, which i have to display. the error is occuring bcoz of statement below both count . I have to sub both cnt
of_study_sites_without_rand_subj_gt AS
(
SELECT
tu.tu_status, tu.tr_no,
case when ((asswors- SSWORGT30) then 'of_study_sites_without_rand_subject<30_days' END) SSW0RLT30
, case when ((asswors- SSWORGT60) then 'of_study_sites_without_rand_subject<30_days' END) SSW0RLT60
, case when ((asswors- SSWORGT90) then 'of_study_sites_without_rand_subject<30_days' END) SSW0RLT90
from
( SELECT
tu.tu_status, tu.tr_no,
COUNT ( CASE WHEN tue.fst_init_vst_act_dt IS NOT NULL THEN tr.tr_alias_cd END ) act_study_site_init,
COUNT ( CASE WHEN tue.fst_subj_rnd_act IS NOT NULL AND tu.tu_status= 'recruiting' THEN tr.tr_alias_cd END ) actual_with_rnd_rec,
CASE WHEN (((act_study_site_init) - (actual_with_rnd_rec) AND tu.tu_status= 'nonrecruiting' then 'act_study_site_without_rnd_subj' END) asswors,
CASE WHEN tue.fst_subj_rnd_act IS NULL then trunc(sysdate)- trunc(tue.fst_init_vst_act_dt )
else trunc ( tue.fst_subj_rnd_act ) - trunc ( tue.fst_init_vst_act_dt )
END daycal,
case when daycal>=30 then count(tr.tr_alias_cd) END SSWORGT30 --of study sites without randomised subject ≥ 30 days
, case when daycal>=60 then count(tr.tr_alias_cd) END SSWORGT60 --of study sites without randomised subject ≥ 60 days
, case when daycal>=30 then count(tr.tr_alias_cd) END SSWORGT90 --of study sites without randomised subject ≥ 90 days
FROM da_cox.dm_ctm_tu tu
INNER JOIN da_cox.dm_ctm_tr tr ON tr.tr_no = tu.tr_no
LEFT OUTER JOIN da_cox.df_ctm_tu_evnt tue
ON tue.curr_flg = 1
AND tue.tu_id = tu.tu_id
WHERE
tu.curr_flg = 1 /* Study sites that have been cancelled after initiation are counted as initiated */
GROUP BY
tu.tr_no,
tu.tu_status,
tr.tr_alias_cd
Getting error in first select
case when ((asswors- SSWORGT30) then 'of_study_sites_without_rand_subject<30_days' END) SSW0RLT30
ORA-00920: invalid relational operator
This error message indicates the problem lies in this part of the statement:
when ((asswors- SSWORGT30) then
You have a test but no condition. The statement expects something like
when ((asswors- SSWORGT30) <= 30 then
That is, if the result of the given sum is less than or equal 30 your case statement will return the string you have after THEN.
Related
Oracle SQL Developer noob here. I am trying to create a quarterly sales analysis based on warehouse names and output the Quarterly sales as Q1, Q2 etc. Using Drill down query concepts.
I am unsure if what I am doing is in any way related to a Drill Down concept but this is one of my many attempts. I am hoping for a way to remove the null value outputs to be left with proper data.
It is in the hopes that with the removal of the null data, all the outputs related to specific warehouse names will also all output to 1 line. Leaving me with Warehouse_Name(1), Q1 Data, Q2 Data, etc
I am currently using two tables for this query which are
Warehouse: Warehouse_id, warehouse_name and quantity_sold
Time_Period: Date_id, Full_date, Days, Month_short and year.
My Code is as follows:
SELECT TO_CHAR(Full_date, 'Q') AS MY_QTR,
Sum(Quantity_sold) AS HOW_MANY_SOLD_PER_QTR
FROM warehouse, Time_Period
GROUP BY TO_CHAR(Full_date, 'Q')
ORDER BY 1;
Select warehouse_Name,
case
when TO_CHAR(Full_date, 'Q') = 1
then Sum(Quantity_sold)
End as Q1_2019,
case
when TO_CHAR(Full_date, 'Q') = 2
then Sum(Quantity_sold)
End as Q2_2019,
case
when TO_CHAR(Full_date, 'Q') = 3
then Sum(Quantity_sold)
End as Q3_2019,
case
when TO_CHAR(Full_date, 'Q') = 4
then Sum(Quantity_sold)
End as Q4_2019
FROM warehouse w1, Time_Period t1
where Q1_2019 IS NOT NULL
GROUP BY warehouse_Name,TO_CHAR(Full_date, 'Q')
ORDER BY 1;
Which provides me with an output of
Waarehouse_Name Q1 Q2 Q3 Q4
--------------- ---- ---- ---- ----
Henderson 990 Null Null Null
Henderson Null 1001 Null Null
Henderson Null Null 1012 Null
Henderson Null Null Null 1012
Edit :
As mentioned by #mathguy
“He was using conditional SUM (conditional by quarter) and also was grouping by quarter in the GROUP BY clause. If you remove the quarter from GROUP BY (which you eventually did), there would be no more null in the output already. The main point of the answer has noting to do with adding else 0 to the case expressions. “
So using else here is unnecessary
Removing quarter from GROUP BY does the thing.
Select warehouse_Name, SUM( case when TO_CHAR(Full_date, 'Q') = 1 then Quantity_sold else 0 End) as Q1_2019,
SUM( case when TO_CHAR(Full_date, 'Q') = 2 then Quantity_sold else 0 End) as Q2_2019,
SUM( case when TO_CHAR(Full_date, 'Q') = 3 then Quantity_sold else 0 End) as Q3_2019,
SUM( case when TO_CHAR(Full_date, 'Q') = 4 then Quantity_sold else 0 End) as Q4_2019
FROM warehouse w1
where Full_date IS NOT NULL
GROUP BY warehouse_Name
ORDER BY 1;
select RP.COUNTRYID,RP.PRDCODE,
RP.REPID,
RP.CHANNELID,
RP.CUSTOMERID,
RP.DIVISION,
RP.WWCOGS_GAUSS,
RP.WWCOGS_SAP,
RP.WWCOGS_BusLine,
RP.CURRID ,
ADD_MONTHS(to_date('01-01-'||rp.year,'DD-MM-YYYY'),level-1) KFDATE
from
(SELECT CP.COUNTRYID,
CP.PRDCODE,
CP.REPID,
CP.CHANNELID,
CP.CUSTOMERID,
IP.DIVISION,
CP.WWCOGS_GAUSS,
CP.WWCOGS_SAP,
CP.WWCOGS_BusLine,
CP.year,
CP.CURRID from
(select distinct IBC.COUNTRYID ,
decode(ls.dmdunit,null,mwa.ProductName,ls.dmdunit) PRDCODE,
ReportingUnit REPID,
'99' CHANNELID,
IBC.COUNTRYID CUSTOMERID ,
(
CASE
WHEN MWA.COGSSourceCF LIKE '%Gauss%'
THEN MWA.COGSPriceCF * MWA.ExchRate
ELSE NULL
END) WWCOGS_GAUSS,
(
CASE
WHEN MWA.COGSSourceCF LIKE '%SAP%'
THEN MWA.COGSPriceCF * MWA.ExchRate
ELSE NULL
END) WWCOGS_SAP,
(
CASE
WHEN MWA.COGSSourceCF NOT LIKE '%Gauss%'
AND MWA.COGSSourceCF NOT LIKE '%SAP%'
THEN MWA.COGSPriceCF * MWA.ExchRate
ELSE NULL
END) WWCOGS_BusLine,
mwa.year,
IRC.CURRID
from BAM.M_WWCOGS_AREA MWA,
MICSTAG.M_IBP_REPUNIT_CURRENCY IRC,
micstag.M_IBP_BDREPORTINGCOUNTRY IBC
,MICSTAG.M_LOCALPRODUCT_STAG LS
WHERE MWA.ReportingUnit=IRC.REPID
--and mwa.productname='FR21030390085'
--and MWA.GaussCountry='BE BELGIUM'
AND IBC.COUNTRYPLANNINGGROUP =MWA.GaussCountry
and IBC.businessdivision=31
and MWA.COGSPriceCF <>0
and ls.REPORTINGUNITID(+)=mwa.ReportingUnit
and ls.IBPLOCALPRDID(+)= mwa.ProductName ) CP, micstag.M_IBP_PRODUCT IP
where CP.PRDCODE=IP.PRDID) RP
CONNECT BY level <= 12 ;
the above query is getting unwanted duplicate, if i use distinct the query is running forever.
req. duplicate the records based on year in result set of rp
consider value of year is 2019 than 12 records should came from 1-jan-2019 to 1-dec-2019.
more than one value of year are possible
The CONNECT BY LEVEL <= 12 trick works nicely with dual because that table returns one row. Things are messier when they base result set returns more than one row, because the CONNECT BY generates a product. This is why you're getting duplicates.
What you need to do is specify some additional criteria for the connection. Ideally you will have a primary key in the projection - I'm going to assume it's REPID, so if it's something different you'll need to tweak this. Anyway, you'll need something like this:
) RP
CONNECT BY level <= 12
and rp.repid = prior rp.repid
and prior sys_guid() is not null
The prior sys_guid() bit prevents ORA-01436: CONNECT BY loop in user data.
Write a procedure that calculates and displays total income from all sources of all hotels. Totals must be printed by month, and for each month by event and service type. Include discounts.( 10% discount if the reservation date is 2 month before reservation start date).
The tables are:
Hotel Table has:
Hotel_id, hotel_name, Hotel_city, Hotel_state, Hotel_zip,Hotel_phone
Reservation Table has:
Reservation_id, Hotel_id, Room_num, Service_id, Guest_name, Reservation_date, Reservation_start_date, Reservation_end_date, cancelation_date, Num_of_guest, event_type
Room Table has:
Room_num, Hotel_id, Room_type, Room_capacity, Room_cost
service table has:
service_id, Service_type, Service_cost
This is what I tried, but I want to write it in a procedure form; how do I do that? Please help. Thanks
select month (Reservation_end_date) as , event_type,
sum(case when days>= 2 then cost- (cost/100)* 10
else cost) as total_cost)
((select distinct reservation.hotel_id,reservation_date, reservation_start_date,
reservation_end_date, event_type, room.room_type as R_type ,room_cost as R_cost,
months_between(reservation_start_date,reservation_date)as months
from reservation, room
where reservation.hotel_id = room.hotel_id;)
union
(select hotel_name, reservation_date, reservation_start_date,
reservation_end_date, event_type, services_type, services_cost as cost,
months_between(reservation_start_date,reservation_date)as month
from reservation,service, hotel
where reservation.services_id = service.services_id
and reservation.hotel_id = hotel.hotel_id;))
group by month(reservation_end_date),event_type;
The first step is to get the base query right.
To consolidate a set of dates into their common month use trunc(date_col, 'mm'). Presumably room costs and service costs should be calculated on a per night basis.
To calculate the number of nights simply subtract the start date from the end date.
This query should produce the correct result (your stated business rules are incomplete so it's hard to be certain). Like your posted code it has subqueries to calculate the cost of each room reservation and each service reservation. These are aggregated in the outer query:
select to_char(r_month, 'YYYY-MON') as rpt_month
, event_type
, service_type
, sum ( (r_cost - r_discount ) * no_of_nights ) as tot_cost
from (
select trunc(r.reservation_end_date , 'mm') as r_month
, r.event_type
, cast(null as varchar2(10)) as service_type
, rm.room_cost as r_cost
, case when months_between (r.reservation_start_date, r.reservation_date) >= 2
then rm.room_cost * 0.1
else 0 end as r_discount
, (r.reservation_end_date - r.reservation_start_date ) as no_of_nights
from reservation r
join room rm
on ( r.room_num = rm.room_num
and r.hotel_id = rm.hotel_id )
union all
select trunc(r.reservation_end_date , 'mon') as r_month
, r.event_type
, sv.service_type
, sv.service_cost as r_cost
, case when months_between (r.reservation_start_date, r.reservation_date) >= 2
then sv.service_cost * 0.1
else 0 end as r_discount
, (r.reservation_end_date - r.reservation_start_date ) as no_of_nights
from reservation r
join service sv
on ( r.service_id = sv.service_id )
)
group by r_month
, event_type
, service_type
order by r_month
, event_type
, service_type
;
The second step is put this into a procedure. Again your requirements are fuzzy: should the procedure take any parameters? what format should the output be in? As the business domain (hotel bookings) and the format of the question ("write a procedure that ...") this appears to be a homework assignment so here is the simplest interpretation of "display". It uses dbms_output routines to print to the screen, and rpad() and lpad() to give a nice layout (obviously the spacings may be wonky, because you haven't provide the datatypes of the various columns) .
create or replace procedure display_monthly_reservations as
begin
<< heading >>
dbms_output.put(rpad('MONTH', 8));
dbms_output.put( rpad('EVENT_TYPE' , 20 ) || ' ');
dbms_output.put( rpad('SERVICE_TYPE', 20 ) || ' ');
dbms_output.put_line('TOTAL_COST');
<< per_line >>
for r in (
<< insert the query here >>
) loop
dbms_output.put(r.rpt_month || ' ');
dbms_output.put( rpad(r.event_type , 20 ) || ' ');
dbms_output.put( rpad(r.service_type , 20 ) || ' ');
dbms_output.put_line( lpad(to_char(r.tot_cost , '9999999.99'), 10 ) );
end loop per_line;
end display_monthly_reservations;
/
Can you please help me in getting a query for this scenario. In below case it should return me single row of A=13 because 13,14 in column A has most occurrences and value of B (30) is greater for 13. We are interested in maximum occurrences of A and in case of tie B should be considered as tie breaker.
A B
13 30
13 12
14 10
14 25
15 5
In below case where there are single occurrence of A (all tied) it should return 14 having maximum value of 40 for B.
A B
13 30
14 40
15 5
Use case - we get calls from corporate customers. We are interested in knowing during what hours of day when most calls come and in case of tie - which of the busiest hours has longest call.
Further question
There is further questions on this. I want to use either of two solutions - '11g or lower' from #GurV or 'dense_rank' from #mathguy in bigger query below how can I do it.
SELECT dv.id , u.email , dv.email_subject AS headline , dv.start_date , dv.closing_date, b.name AS business_name, ls.call_cost, dv.currency,
SUM(lsc.duration) AS duration, COUNT(lsc.id) AS call_count, ROUND(AVG(lsc.duration), 2) AS avg_duration
-- max(extract(HOUR from started )) keep (dense_rank last order by count(duration), max(duration)) as most_popular_hour
FROM deal_voucher dv
JOIN lead_source ls ON dv.id = ls.deal_id
JOIN lead_source_call lsc ON ls.PHONE_SID = lsc.phone_number_id
JOIN business b ON dv.business_id = b.id
JOIN users u ON b.id = u.business_id
AND TRUNC(dv.closing_date) = to_date('13-01-2017', 'dd-mm-yyyy')
AND lsc.status = 'completed' and lsc.duration >= 30
GROUP BY dv.id , u.email , dv.email_subject , dv.start_date , dv.closing_date, b.name, ls.call_cost, dv.currency
--, extract(HOUR from started )
Try this if 12c+
select a
from t
group by a
order by count(*) desc, max(b) desc
fetch first 1 row only;
If 11g or lower:
select * from (
select a
from t
group by a
order by count(*) desc, max(b) desc
) where rownum = 1;
Note that if there is equal count and equal max value for two or more values of A, then any one of them will be fetched.
Here is a query that will work in older versions (no fetch clause) and does not require a subquery. It uses the first/last function. In case of ties by both "count by A" and "value of max(B)" it selects only the row with the largest value of A. You can change that to min(A), or even to sum(A) (although that probably doesn't make sense in your problem) or LISTAGG(A, ',') WITHIN GROUP (ORDER BY A) to get a comma-delimited list of the A's that are tied for first place, but that requires 11.2 (I believe).
select max(a) keep (dense_rank last order by count(b), max(b)) as a
, max(max(b)) keep (dense_rank last order by count(b)) as b
from inputs
group by a
;
select
case when exists (select "CreatedOn" dategn from "RentedVehicle" where "fkTempVehicleId"=3)
then
case when exists (select "CreatedOn" dategn from "Transfer" where "fkTempVehicleId"=3)
then
(select
case when rent.dategn>tran.dategn then rent.dategn else tran.dategn end dategn,
case when rent.dategn>tran.dategn then rent.fuel else tran.fuel end fuel
from
(
select max("CreatedOn") dategn,"CheckInFuel" fuel
from "RentedVehicle" where "fkTempVehicleId"=3
group by "RentedVehicle"."CheckInFuel"
) rent ,
(select max("CreatedOn") dategn,"fkFuelLevelId" fuel
from "Transfer" where "fkTempVehicleId"=3 group by "Transfer"."fkFuelLevelId") tran)
else
(select
max("CreatedOn") dategn,"CheckInFuel" fuel
from "RentedVehicle" where "fkTempVehicleId"=3 group by "RentedVehicle"."CheckInFuel") end
else
case when exists (select "CreatedOn" dategn from "Transfer" where "fkTempVehicleId"=3)
then
(select max("CreatedOn") dategn,"fkFuelLevelId" fuel
from "Transfer" where "fkTempVehicleId"=3 group by "Transfer"."fkFuelLevelId")
else
(select "CreatedOn" dategn,"InitialFuel" fuel from "TempVehicle" where "pkTempVehicleId"=3)
end end from dual;
it is throwing exception
ORA-00913: too many values
00913. 00000 - "too many values"
*Cause:
*Action:
Error at Line: 6 Column: 2
i am sure i am missing something but i tried almost everything.
please help and elaborate what i missed
Your inline select (part of the case statement) returns two values (dategn and fuel), where only one is allowed:
...
then
(select
case when rent.dategn>tran.dategn then rent.dategn else tran.dategn end dategn,
case when rent.dategn>tran.dategn then rent.fuel else tran.fuel end fuel
from ...
A case can only return a single value per row (as it is called per row).