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.
Related
I have a column MONTHLY_SPEND in the table with data type of NUMBER. I am trying to write a query which will return number of zeros in the column.
e.g..
1000 will return 3
14322 will return 0
1230 will return 1
1254000.65 will return 0
I tried using mod operator and 10 but without the expected result. Any help is appreciated. Please note that database is Oracle and we can't create procedure/function.
select nvl(length(regexp_substr(column, '0+$')), 0) from table;
Here is one way to find
create table spend
(Monthly_spend NUMBER);
Begin
insert into spend values (1000)
insert into spend values (14322)
insert into spend values (1230)
insert into spend values (1254000.65)
End;
This query will for this data :
select Monthly_spend,REGEXP_COUNT(Monthly_spend,0)
from spend
where Monthly_spend not like '%.%' ;
if have one more data like 102 and if it should be zero , then try below query:
select Monthly_spend,case when substr(Monthly_spend,-1,1)=0 THEN REGEXP_COUNT(Monthly_spend,0) ELSE 0 END from spend;
Here is final query for value like 2300120 or 230012000
select Monthly_spend,
case when substr(Monthly_spend,-1,1)=0 and REGEXP_COUNT(trim (0 from Monthly_spend),0)<=0 THEN REGEXP_COUNT(Monthly_spend,0)
when REGEXP_COUNT(trim (0 from Monthly_spend),0)>0 THEN LENGTH(Monthly_spend) - LENGTH(trim (0 from Monthly_spend))
ELSE 0 END from spend;
Output :
1000 3
1254000.65 0
14322 0
1230 1
102 0
2300120 1
230012000 3
You can try this, a simple solution.
select length(to_char(col1))-length(rtrim(to_char(col1), '0')) no_of_trailing_zeros from dual;
select length(to_char('123.120'))-length(rtrim(to_char('123.120'), '0')) no_of_trailing_zeros from dual;
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
I have to deal with a little problem in Oracle...I have a table with 2 columns, the first column contains dates, the second one contains imports. The "import column" could have both NULL or not NULL values.
What I want to do is to order by the date column (and this is easy :) ) and then split the table in blocks of contiguous NULL or not NULL values in the "import column" adding a third column which numbers the blocks.
Example:
Date Import
01/01/2017 99.12
01/02/2017 18.19
01/03/2017 22.92
01/04/2017 28.10
01/05/2017
01/06/2017
01/07/2017
01/08/2017 33.78
01/09/2017 20.30
01/10/2017 12.33
01/11/2017
01/12/2017 1.68
this table should became
Date Import Block
01/01/2017 99.12 1
01/02/2017 18.19 1
01/03/2017 22.92 1
01/04/2017 28.10 1
01/05/2017 2
01/06/2017 2
01/07/2017 2
01/08/2017 33.78 3
01/09/2017 20.30 3
01/10/2017 12.33 3
01/11/2017 4
01/12/2017 1.68 5
You can use analytic functions like this:
select d, import, sum(state_change) over (order by d) as block
from
(
select d, import, import_state,
case when import_state = lag(import_state) over (order by d, import)
then 0 else 1 end state_change
from
(
select d, import, case when import is not null then 1 else 0 end as import_state
from t
)
);
(NB I renamed your DATE column to D as DATE is a reserved word).
Breaking it down, starting with the innermost query:
select d, import, case when import is not null then 1 else 0 end as import_state
from t
This adds a column import_state that is 1 when import is not null, 0 if it is null. This creates "blocks" but they are numbered 1,0,1,0,... instead of 1,2,3,4,...
The next part compares each import_state with that on the preceding row, to check for changes. Column state_change is 1 when there has been a change, 0 otherwise - so now the first row for each "block" has a 1 and the reset have a 0.
The outer part then simply sums the state_change values cumulatively to give the required result.
There may well be a simpler solution!
Need a help for Hive query.
I wrote a Hive query :
select to_date(from_unixtime(epoch)) as date, count1 , count2, count3 from table1 where count3=168
This gives me result as follows:
date count1 count2 count3
7-15-2015 168 3 7
7-15-2015 168 1 5
7-15-2015 168 4 3
and similarly for other dates
....
Finally i need to write a query which returns me, median value of count2 and count3 for each date.
for ex: I need output as:
date count1 count2 count3
7-15-2015 168 3 5
and similarly for other dates
I know i need to use group by date and then write subquery on that.
But I am not able to write correct query.
Can anyone help me in this
The median is the 2nd quartile, 5th decile, and 50th percentile. We can calculate the 50th percentile using percentile function in hive:
select to_date(from_unixtime(epoch)) as date
, count1
, percentile(count2,0.5) as median_ct2
, percentile(count3,0.5) as median_ct3
from table1
where count1=168
group by to_date(from_unixtime(epoch)), count1;
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