I come from a MySQL background and am having problems with the following query:
SELECT DISTINCT agenda.idagenda AS "ID_SERVICE", agenda.name AS "ID_SERVICE_NAME", specialities.id AS "ID_DEPARTMENT", specialities.name AS "ID_DEPARTMENT_NAME",
supervisor.clients_waiting AS "CWaiting",
(CASE WHEN supervisor.clients_resent_waiting_area IS NULL THEN 0 ELSE supervisor.clients_resent_waiting_area END) AS "CWaiting_Resent_Area",
supervisor.clients_attending AS "CAttending",
supervisor.clients_attended AS "CAttended",
(SELECT MAX(ROUND((SYSDATE-core.supervisor_time_data.time_attending)*86400)) FROM dual) AS "MTA",
(SELECT MAX(ROUND((SYSDATE-core.supervisor_time_data.time_waiting)*86400)) FROM dual) AS "MTE",
(SELECT SUM(SYSDATE-supervisor_time_data.time_attending)*86400 FROM dual)/(SELECT supervisor.clients_attending FROM dual) AS "TMA",
(SELECT SUM(SYSDATE-supervisor_time_data.time_waiting)*86400 FROM dual)/(SELECT supervisor.clients_waiting FROM dual) AS "TME",
supervisor.tme_accumulated AS "TME_ACCUMULATED",
supervisor.tma_accumulated AS "TMA_ACCUMULATED",
(CASE WHEN agenda.alarm_cee IS NULL THEN 0 ELSE agenda.alarm_cee END) AS "ALARM_CEE",
(CASE WHEN agenda.alarm_mte IS NULL THEN 0 ELSE agenda.alarm_mte END) AS "ALARM_MTE",
(CASE WHEN agenda.alarm_mta IS NULL THEN 0 ELSE agenda.alarm_mta END) AS "ALARM_MTA",
(CASE WHEN agenda.alarm_tme IS NULL THEN 0 ELSE agenda.alarm_tme END) AS "ALARM_TME"
FROM CORE.supervisor
LEFT JOIN CORE.supervisor_time_data ON supervisor_time_data.id_service = supervisor.id_service
LEFT JOIN CORE.agenda ON supervisor.id_service = agenda.id
LEFT JOIN CORE.specialities ON agenda.idspeciality = specialities.id
WHERE supervisor.booked_or_sequential = 1
GROUP BY agenda.idagenda, agenda.name, supervisor.id_service, specialities.id, specialities.name, supervisor.clients_waiting, supervisor.clients_resent_waiting_area,
supervisor.clients_attending, supervisor.clients_attended,
supervisor_time_data.time_attending, supervisor_time_data.time_waiting,
supervisor.tme_accumulated, supervisor.tma_accumulated, agenda.alarm_cee, agenda.alarm_mte,agenda.alarm_mta,agenda.alarm_tme;
It should return two records, but instead it's returning four. ID_SERIVE is returning 3 records with the same value.
"ID_SERVICE" "ID_SERVICE_NAME" "ID_DEPARTMENT" "ID_DEPARTMENT_NAME" "CWaiting" "CWaiting_Resent_Area" "CAttending" "CAttended" "MTA" "MTE" "TMA" "TME" "TME_ACCUMULATED" "TMA_ACCUMULATED" "ALARM_CEE" "ALARM_MTE" "ALARM_MTA" "ALARM_TME"
"DR" "DR" 1 "SECUENCIALES" 1 0 1 1 5504 5504 21 109 0 0 0 0
"DR" "DR" 1 "SECUENCIALES" 1 0 1 1 1590 1590.000000000000000000000000000000000002 21 109 0 0 0 0
"DR" "DR" 1 "SECUENCIALES" 1 0 1 1 21 109 0 0 0 0
"TRAU" "TRAU" 1 "SECUENCIALES" 1 0 0 0 1567 1567.000000000000000000000000000000000002 0 0 0 0 0 0
What am I doing wrong?
Thanks
You seem to be including all the columns you're interesting in the group by, and not aggregating properly; possibly you've got to this point by trial and error as you've tried to resolve errors from columns not being grouped. You don't need the sub-selects in all the column clauses.
Untested as we don't have your tables or raw data but it looks like you want something like:
SELECT agenda.idagenda AS "ID_SERVICE",
agenda.name AS "ID_SERVICE_NAME",
specialities.id AS "ID_DEPARTMENT",
specialities.name AS "ID_DEPARTMENT_NAME",
supervisor.clients_waiting AS "CWaiting",
NVL(supervisor.clients_resent_waiting_area, 0) AS "CWaiting_Resent_Area",
supervisor.clients_attending AS "CAttending",
supervisor.clients_attended AS "CAttended",
MAX(ROUND((SYSDATE - supervisor_time_data.time_attending)*86400)) AS "MTA",
MAX(ROUND((SYSDATE - supervisor_time_data.time_waiting)*86400)) AS "MTE",
SUM(SYSDATE - supervisor_time_data.time_attending)*86400
/ supervisor.clients_attending AS "TMA",
SUM(SYSDATE - supervisor_time_data.time_waiting)*86400
/ supervisor.clients_waiting AS "TME",
supervisor.tme_accumulated AS "TME_ACCUMULATED",
supervisor.tma_accumulated AS "TMA_ACCUMULATED",
NVL(agenda.alarm_cee, 0) AS "ALARM_CEE",
NVL(agenda.alarm_mte, 0) AS "ALARM_MTE",
NVL(agenda.alarm_mta, 0) AS "ALARM_MTA",
NVL(agenda.alarm_tme, 0) AS "ALARM_TME"
FROM CORE.supervisor
LEFT JOIN CORE.supervisor_time_data
ON supervisor_time_data.id_service = supervisor.id_service
LEFT JOIN CORE.agenda ON supervisor.id_service = agenda.id
LEFT JOIN CORE.specialities ON agenda.idspeciality = specialities.id
WHERE supervisor.booked_or_sequential = 1
GROUP BY agenda.idagenda, agenda.name, supervisor.id_service, specialities.id,
specialities.name, supervisor.clients_waiting,
supervisor.clients_resent_waiting_area, supervisor.clients_attending,
supervisor.clients_attended, supervisor.tme_accumulated,
supervisor.tma_accumulated, agenda.alarm_cee,
agenda.alarm_mte,agenda.alarm_mta,agenda.alarm_tme;
So specifically, supervisor_time_data.time_waiting and supervisor_time_data.time_attending don't need to be in the group by as they are used in aggregate.
I've replaced your case checks with nvl just because it's shorter; case is fine though if you prefer that.
Related
I'm trying to analyze an existing oracle query. I am not well versed in Oracle and I'm bit confused by the use of this NVL function in DECODE function
Select
DECODE (DECODE(NVL(tab.id,0),0,0,1)+ DECODE (NVL(tab2.id,0),0,01), 2,'two', 0,'none',
DECODE (DECODE (NVL(tab2.id,0),0,0,1),1,'one','NA')
) Result
The tables are contains below values.
Tab
count id
1 1111
0 null
1 2222
1 3333
1 4444
1 5555
tab2
count id
1 1111
1 3333
1 6666
1 2222
0 null
How does a DECODE function work here?
How does a DECODE function work here?
DECODE is a function-based equivalent of a CASE statement.
Your code is the equivalent of:
Select CASE DECODE(NVL(tab.id,0),0,0,1)
+ DECODE (NVL(tab2.id,0),0,0,1),
WHEN 2 THEN 'two'
WHEN 0 THEN 'none'
ELSE DECODE(DECODE (NVL(tab2.id,0),0,0,1),1,'one','NA')
END AS Result
You can then expand out the nested DECODEs and NVLs to:
Select CASE CASE
WHEN tab.id IS NULL OR tab.id = 0 THEN 0
ELSE 1
END
+
CASE
WHEN tab2.id IS NULL OR tab2.id = 0 THEN 0
ELSE 1
END,
WHEN 2 THEN 'two'
WHEN 0 THEN 'none'
ELSE CASE CASE
WHEN tab2.id IS NULL OR tab2.id = 0 THEN 0
ELSE 1
END
WHEN 1 THEN 'one'
ELSE 'NA'
END
END AS Result
In English:
Covert each of tab.id and tab2.id to zero, if their values are either zero or NULL, or to one and then add the two values together.
If their total is zero or two then return the total in words.
If their total is one then check the tab2.id value on its own and if its value is not zero or NULL then return (in words) one.
Otherwise, it must have been tab.id that was not zero or NULL and return NA.
I want to merge two columns(Sender and Receiver) and get the Transaction Type count then merge another table with using Sender_Receiver primary id.
Sender Receiver Type Amount Date
773787639 777611388 1 300 2/1/2019
773631898 776806843 4 450 8/20/2019
773761571 777019819 6 369 2/11/2019
774295511 777084440 34 1000 1/22/2019
774263079 776816905 45 678 6/27/2019
774386894 777202863 12 2678 2/10/2019
773671537 777545555 14 38934 9/29/2019
774288117 777035194 18 21 4/22/2019
774242382 777132939 21 1275 9/30/2019
774144715 777049859 30 6309 7/4/2019
773911674 776938987 10 3528 5/1/2019
773397863 777548054 15 35892 7/6/2019
776816905 772345091 6 1234 7/7/2019
777035194 775623065 4 453454 7/20/2019
Second Table
Mobile_number Age
773787639 34
773787632 23
774288117 65
I am try to get like this kind of table
Sender/Receiver Type_1 Type_4 Type_12...... Type_45 Age
773787639 3 2 0 0 23
773631898 1 0 1 2 56
773397863 2 2 0 0 65
772345091 1 1 0 3 32
Ok, I have seen your old question and you just need inner join in sub-query as following:
SELECT
SenderReceiver,
COUNT(CASE WHEN Type = 1 THEN 1 END) AS Type_1,
COUNT(CASE WHEN Type = 2 THEN 1 END) AS Type_2,
COUNT(CASE WHEN Type = 3 THEN 1 END) AS Type_3,
...
COUNT(CASE WHEN Type = 45 THEN 1 END) AS Type_45,
Age -- changes here
FROM
( SELECT sr.SenderReceiver, sr.Type, st.Age from -- changes here
(SELECT Sender AS SenderReceiver, Type FROM yourTable
UNION ALL
SELECT Receiver, Type FROM yourTable) sr
join <second_table> st on st.Mobile_number = sr.SenderReceiver -- changes here
) t
GROUP BY
SenderReceiver,
Age; -- changes here
Changes done in your previous query are marked with comments -- changes here.
Please replace the name of the <second_table> with the original name of the table.
Cheers!!
Hi I have a dataframe as below with thousands of ID's. It has a list of ID's which have sub id's within them as shown. The subid's may get changed on daily basis, either a new sub id may be added, or an existing sub id maybe lost.
I need to create 2 new columns, which will flag whenever a sub id is added/lost.
So, in the below format you can see that on the 12th, a new sub id 'D' is added
and on the 13th, and existing sub id (c) is lost.
i want to create a new column/flag to track these sub ids. Can you please help me with this?
I am using Python 3.5. Thanks
Sample format for one ID:
ID Sub Id Date is_new
1 a 3/11/2016 0
1 b 3/11/2016 0
1 c 3/11/2016 0
1 a 3/12/2016 0
1 b 3/12/2016 0
1 c 3/12/2016 0
1 d 3/12/2016 1
1 a 3/13/2016 0
1 b 3/13/2016 0
1 d 3/13/2016 0
Below query will indicate when a sub-id is added or deleted. Hope this helps.
Get the max and min update date per id, I put it in a temp table name: min_max
If update date is same with min and max then mark them as 1
Lag and lead functions will get the previous and next sub id per ID, subid order by
Put everything on a subquery (table s)
If update date is not the start or end date per ID, then it can be added (is_mindte=0) or deleted (is_maxdte=0)
If is_added column is null, then it is added on that date (is_added is null); If is_deleted column is null, then it is deleted the next update date (is_added is null)
select s.id,
s.subid,
s.upddate,
(case when is_mindte=0 and is_added is null
then 1 else 0 end ) is_new,
(case when is_maxdte=0 and is_deleted is null
then 1 else 0 end) is_removed
from (
with min_max as
(select id,min(upddate) mindate,max(upddate) maxdate
from myTable
group by id)
select t.id,
t.subid,
t.upddate,
case when t.upddate=m.mindate
then 1 else 0 end is_mindte,
case when t.upddate=m.maxdate
then 1 else 0 end is_maxdte,
lag(t.subid) over (partition by t.id, t.subid order by t.upddate) is_added,
lead(t.subid) over (partition by t.id, t.subid order by t.upddate) is_deleted
from myTable t, min_max m
where t.id=m.id) s
order by s.id,
s.upddate,
s.subid
sample result:
ID SUBID UPDDATE IS_NEW IS_REMOVED
1 a 2016-03-11T00:00:00Z 0 0
1 b 2016-03-11T00:00:00Z 0 0
1 c 2016-03-11T00:00:00Z 0 0
1 a 2016-03-12T00:00:00Z 0 0
1 b 2016-03-12T00:00:00Z 0 0
1 c 2016-03-12T00:00:00Z 0 1
1 d 2016-03-12T00:00:00Z 1 0
1 a 2016-03-13T00:00:00Z 0 0
1 b 2016-03-13T00:00:00Z 0 0
1 d 2016-03-13T00:00:00Z 0 0
2 a 2016-03-11T00:00:00Z 0 0
2 b 2016-03-11T00:00:00Z 0 0
2 c 2016-03-11T00:00:00Z 0 0
Oracle behaves really extrange with the next query:
I am trying to evaluate these three records, one of them should show the column digitado = 1 because it accomplishes all the conditions, which are, NUM_DOCUMENTO_ENCABEZADO iS NOT NULL and ORIGEN_PLANILLA = 2
NUM_DOCUMENTO NUM_DOCUMENTO_ENCABEZADO ORIGEN_PLANILLA
8220568059 8220568059 2
8220681644 2
940723593097 1
select x.num_documento,
x.origen_planilla,
x.num_documento_encabezado,
case
when x.num_documento_encabezado > '0' and x.origen_planilla = 2 then
1
else
0
end digitado
from (
select h.num_documento,
h.num_documento_encabezado,
h.origen_planilla
from (
select a.num_documento,
c.num_documento num_documento_encabezado,
case when NVl(UPPER(a.txt_observacion),'X') like '%SGP%' THEN 1 ELSE 2 END origen_planilla
from epsis.ryc_recaudo a,
epsis.ryc_recaudo_unificado b,
epsis.ryc_documento_encabezado c
where a.fec_pago >= to_date('28082013','ddmmyyyy') ---aca se coloca el dia del ultimo proceso,
and a.fec_pago < to_date('25092013','ddmmyyyy')-- el cecaudo viene un dia atrasados
and b.num_documento(+) = a.num_documento
and c.num_documento(+) = b.num_documento --80595
and a.num_documento in ( '940723593097', '8220681644','8220568059')
) h,
epsis.ryc_divide_documento f,
epsis.ryc_documento_encabezado g
where f.num_documento(+) = h.num_documento
and g.num_documento(+) =f.num_division
group by h.num_documento,
h.num_documento_encabezado,
h.origen_planilla
) x
This is the result:
NUM_DOCUMENTO ORIGEN_PLANILLA NUM_DOCUMENTO_ENCABEZADO DIGITADO
8220568059 2 8220568059 0
8220681644 2 0
940723593097 1 0
The column DIGITADO should be "1" for the first record.
Oracle can not evaluate this "CASE" properly:
case
when x.num_documento_encabezado > '0' and x.origen_planilla = 2 then
1
else
0
end digitado
I have tried diferent things, for example if I change the previous code for this:
case
when length(x.num_documento_encabezado||x.origen_planilla) > 1 then
1
else
0
end digitado
This is the result:
NUM_DOCUMENTO ORIGEN_PLANILLA NUM_DOCUMENTO_ENCABEZADO DIGITADO
8220568059 2 8220568059 1
8220681644 2 0
940723593097 1 0
It works for every record, but that is not the point, the point is that oracle is not able to evaluate the "AND" expression, and the ortiginal query is much longer than the example displayed.
Now, another extrange this is that, when I execute the query only for the record that is ok, I mean this
and a.num_documento in ('8220568059')
the "AND" expression in the case sentence works properly with the original "CASE".
Result:
NUM_DOCUMENTO ORIGEN_PLANILLA NUM_DOCUMENTO_ENCABEZADO DIGITADO
8220568059 2 8220568059 1
Another thing is that, and here is where i believe the problem is, when no outer join in the second subquery, then the query runs ok, but I need that outer join, I am talking about this:
where f.num_documento(+) = h.num_documento
and g.num_documento(+) =f.num_division
I really don't want to rewrite the full query, does anyone know why this happen?
Create and insert statements, these ones reproduce the issue
create table tmp_origin
(
doc varchar2(30),
val number,
obs varchar2(30)
);
create table tmp_uni
(
doc varchar2(30),
doc_origin varchar2(30)
);
create table tmp_div
(
doc varchar2(30),
doc_div varchar2(30)
);
insert into tmp_origin values ('8220568059',100000, 'NORMAL');
insert into tmp_origin values ('8220681644',200000, 'NORMAL');
insert into tmp_origin values ('940723593097',300000, 'SGP');
commit;
insert into tmp_uni values ('8220568059','8220568059');
commit;
This is the query adapted to the above lines, I have also added some others cases, so you can compare and identify that the first one is not working
select x.num_documento,
x.origen_planilla,
x.num_documento_encabezado,
case
when x.num_documento_encabezado is not null and x.origen_planilla = 2 then
1
else
0
end digitado,
case
when length(x.num_documento_encabezado||x.origen_planilla) > 1 then
1
else
0
end digitado2,
case
when x.origen_planilla = 2 then
case
when x.num_documento_encabezado is not null then
1
else
0
end
else
0
end digitado3
from (
select h.num_documento,
h.num_documento_encabezado,
h.origen_planilla
from (
select a.doc num_documento,
b.doc num_documento_encabezado,
case when NVl(UPPER(a.obs),'X') like '%SGP%' THEN 1 ELSE 2 END origen_planilla
from tmp_origin a,
tmp_uni b
where a.doc in ( '940723593097', '8220681644','8220568059')
and b.doc(+) = a.doc
) h,
tmp_div f
where f.doc(+) = h.num_documento
group by h.num_documento,
h.num_documento_encabezado,
h.origen_planilla
) x
You should almost never use the comparison operators with VARCHAR2, it is almost never useful (except if you are writing a sorting algorithm). In your case especially, it doesn't do what you expect.
When you compare VARCHAR2s, the result will depend upon character ordering (for instance '2' is "greater" than '10' because 2 comes after 1 in the character table).
Consider:
SQL> select * from dual where '8220568059' > '0';
DUMMY
-----
X
SQL> select * from dual where ' 8220568059' > '0';
DUMMY
-----
Always use the right datatype for the right task. There is almost always only one datatype that will work correctly. You should always use NUMBER and explicit datatype conversion when working with numbers:
SQL> select * from dual where to_number('8220568059') > 0;
DUMMY
-----
X
Also if you just want to know if a value is NULL, please use the IS NOT NULL operator:
SQL> WITH DATA AS (
2 SELECT '8220568059' num_documento_encabezado,
3 2 origen_planilla FROM dual UNION ALL
4 SELECT '', 2 FROM dual UNION ALL
5 SELECT '', 1 FROM dual)
6 SELECT x.origen_planilla,
7 x.num_documento_encabezado,
8 CASE
9 WHEN x.num_documento_encabezado IS NOT NULL
10 AND x.origen_planilla = 2 THEN
11 1
12 ELSE
13 0
14 END digitado
15 FROM DATA x;
ORIGEN_PLANILLA NUM_DOCUMENTO_ENCABEZADO DIGITADO
--------------- ------------------------ ----------
2 8220568059 1
2 0
1 0
I have a data set like this
id subid date(in yyyymmdd) time(in hh24miss) count1 count2
80013727 20000000431 20120429 001500 0 0
80013727 20000000431 20120429 003000 0 0
80013729 20000000432 20120429 001500 0 0
80013729 20000000432 20120429 003000 0 0
80013728 20000000435 20120429 001500 0 0
80013728 20000000435 20120429 003000 0 0
As you can see time is in 15 minutes increment . i want to show output the result set like below.
id Date subid 00:00:00-00:14:59 00:15:00-00:29:59
80013727 20120429 20000000431 0 0
80013729 20120429 20000000432 0 0
as you can see all all the data related to id 80013727 i s shown in one row instead of 2 for the date 20120429.
please tell me how to achieve it.
header row can be printed one time using dbms_output.put_line.
Hi here is your answers-
oracle ver 10.2 g
for a unique id,subid,date combination count1 and count2 is need to be shown in one row.
instead of 4 rows that can be seen from top most result set.
80013727 20000000431 20120429 has 2 rows for different time (i.e. 015000,030000)
I need to show
80013727 20000000431 20120429 count1(from 1st row),count1(from 2nd row)
80013727 20000000431 20120429 count2(from 1st row),count2(from 2nd row)
Obviously you have simplified your data and your output structure. I'm guessing you'll end up with 96 count columns (although I'm not going that far either).
with cte as
( select * from your_table )
select id
, subid
, date
, type
, sum(c01) as "00:00:00-00:14:59"
, sum(c02) as "00:15:00-00:29:59"
, sum(c96) as "23:45:00-23:59:59"
from (
select id
, subid
, date
, 'C1' type
, case when time between 0 and 899 then count1 else 0 end as c01
, case when time between 900 and 1799 then count1 else 0 end as c02
, case when time between 85500 and 86399 then count1 else 0 end as c96
from cte
union all
select id
, subid
, date
, 'C2' type
, case when time between 0 and 899 then count2 else 0 end as c01
, case when time between 900 and 1799 then count2 else 0 end as c02
, case when time between 85500 and 86399 then count2 else 0 end as c96
)
group by id, subid, date, type
order by id, subid, date, type
So, this use a sub-query factoring expression to select only once from your table. It uses case() to assign counts to a specific time column, on the basis of a range of seconds. There are two queries to aggregate the counts for lines 1 and 2.
The sum() calls may be unnecessary; it's not clear from your data whether you have more than one record in each time slot.