I am using oracle 11g and have written a stored procedure which stores values in temporary table as follows:
id count hour age range
-------------------------------------
0 5 10 61 10-200
1 6 20 61 10-200
2 7 15 61 10-200
5 9 5 61 201-300
7 10 25 61 201-300
0 5 10 62 10-20
1 6 20 62 10-20
2 7 15 62 10-20
5 9 5 62 21-30
1 8 6 62 21-30
7 10 25 62 21-30
10 15 30 62 31-40
now using this temp table i want to return two cursors. one for 61 and one for 62(age).
and for cursors there distinct range will be columns . for example cursor for age 62 should return following as dataset.
user 10-20 21-30 31-40
Count/hour count/hour count/hour
----------------------------------------------
0 5 10 - - - -
1 6 20 8 6 - -
2 7 15 - - - -
5 - - 9 5 - -
7 - - 10 25 - -
10 - - - - 15 30
this column range in temp table is is not a fixed values these are referenced from other table.
edited: i am using PIVOT for above problem, all examples i saw in internet are there for fixed values of column values (range in my case). how can i get dynamic values. following is the ex query:
SELECT *
FROM (SELECT column_2, column_1
FROM test_table)
PIVOT (SUM(column1) AS sum_values FOR (column_2) IN ('value1' AS a, 'value2' AS b, 'value3' AS c));
Instead of using handwritten value i am using following query inside 'IN'
SELECT * from(
with x as (
SELECT DISTINCT range
FROM test_table
WHERE age = 62 )
select ltrim( max( sys_connect_by_path(range, ','))
keep (dense_rank last order by curr),
',') range
from (select range,
row_number() over (order by range) as curr,
row_number() over (order by range) -1 as prev
from x)
connect by prev = PRIOR curr
start with curr = 1 )
it is giving error in this case. But when i using handwritten values its giving right output.
select * from (select user_id, nvl(count,0) count, nvl(hour,0) hour,nvl(range,0) range,nvl(age,0)
age from test_table)
PIVOT (SUM(count) as sum_count, sum(hour) as sum_hour for (range) IN
(
'10-20','21-30','31-40'
)
) where age = 62 order by userid
how can i give values dynamically there?
how can i do it.
Cursors are slow, I would recommend trying to do this in a query unless there's no alternative (or speed doesn't matter). You may want to look into: PIVOT / UNPIVOT which can rotate columns (in this case "range").
Here's some PIVOT / UNPIVOT documentation and examples:
http://www.oracle-developer.net/display.php?id=506
Based on your last edit:
Pretty sure you have two options:
Build dynamic sql based on the distinct values found in the "range" column.
You'll probably be stuck using a cursor again to build the column names but at least it will be limited to just the distinct ranges.
Oracle has a PIVOT XML command that you can use for this.
See: http://www.oracle.com/technetwork/articles/sql/11g-pivot-097235.html
And scroll down to the section: "XML Type"
Related
I have following table:
Id
offset
length
5000
0
5
5001
5
5
5002
10
4
5003
14
4
5010
23
5
5011
28
5
Offset value in each row is based on summation of offset and length of previous row.
As you can see, 6 rows have been deleted between forth and fifth rows and I need to update again offset column based on regular way. My desired output would be as follow:
Id
offset
length
5000
0
5
5001
5
5
5002
10
4
5003
14
4
5010
18
5
5011
23
5
Is there a pure update SQL statement to achieve this in sqlite?
I Appreciate any help.
If your version of SQLite is 3.33.0+ you can use the UPDATE ... FROM... syntax with SUM() window function:
UPDATE tablename AS t1
SET offset = t2.offset
FROM (
SELECT Id, SUM(length) OVER (ORDER BY Id ROWS BETWEEN UNBOUNDED PRECEDING AND 1 PRECEDING) offset
FROM tablename
) AS t2
WHERE t2.Id = t1.Id AND t2.offset IS NOT NULL;
See the demo.
For previous versions use a correlated subquery:
UPDATE tablename AS t1
SET offset = COALESCE(
(SELECT SUM(t2.length) FROM tablename t2 WHERE t2.Id < t1.Id),
t1.offset
);
See the demo.
I want to compute the time interval that has been needed for pressing the different keys of the keyboard by writing a message.
In order to get the data I use a program that produces a .csv after writing a text. This .csv has three columns: the first one with the key pressed and released, the second column says if the key has been pressed (0) or released (1), and the last column registers the time for each event.
Then the idea is to compute the time interval that has been needed for each key, since it is pressed until it is released.
In the following extra simple example we can see that the key 16777248 has been pressed at time 5.0067901611328125e-06 and released at time 0.21875882148742676, therefore, the time interval for this key is 0.21875882148742676-5.0067901611328125e-06. The time interval for the key 72 should be 0.1861410140991211-0.08675289154052734.
16777248 0 5.0067901611328125e-06
72 0 0.08675289154052734
72 1 0.1861410140991211
16777248 1 0.21875882148742676
At the moment I have written a code in R that, first of all, reads the table in .csv. Then it searchs the first 1 in the second column and takes the corresponding key name. Next, it searchs for the previous key with a 0. It computes the time interval, saves this value in a vector and then deletes this two rows from the matrix. Following, it should repeat this until the are no more rows.
data.csv <- read.table("example.csv",header=F, sep=",", dec=".")
myTable<- data.csv
keySearched=0
timeInterval=c( rep( 0,length(myTable[,1]) ) )
L=(length(myTable[,1]))
for( i in 1:L ){
if( myTable[i,2]==1 ){
keySearched <- myTable[i,1]
for( j in 1:(i-1) ){
if( myTable[j,1]==keySearched ){
timeInterval[j] <- (myTable[i,3]-myTable[j,3])
myTable <- myTable[ -c(j,i), ]
}
}
}
}
The problem is that sometimes the value myTable[x,y] is NA because the corresponding row has been deleted. In each iteration two rows are deleted (the one with the pressed key and the corresponding released key).
At this point I get the following error:
Error in if (myTable[j, 1] == keySearched) { :
missing value where TRUE/FALSE needed
How could I solve this problem?
You could try doing it like this:
key = c(3,6,3,8,8,3,6,3)
pressed = c(0,0,1,0,1,0,1,1)
time = c(12,14,16,17,19,22,34,35)
a = data.frame(key,time,pressed)
>a
key time pressed
1 3 12 0
2 6 14 0
3 3 16 1
4 8 17 0
5 8 19 1
6 3 22 0
7 6 34 1
8 3 35 1
First order your data frame (or matrix if you prefer) by the key number and then the time. This should group pressed and released keys together. Then you calculate the time difference between the same keys using diff. And finally, set to NA those diffs that don't make sense.
a = a[order(a$key,a$time),]
a$lapse = c(0,diff(a$time))
a$lapse[seq(1,nrow(a),2)] = NA
>a
key time pressed lapse
1 3 12 0 NA
3 3 16 1 4
6 3 22 0 NA
8 3 35 1 13
2 6 14 0 NA
7 6 34 1 20
4 8 17 0 NA
5 8 19 1 2
In google BigQuery I have done a simple query to get how many music someone has listened.
What I need is to make a sum for all rows returned from the query below (some type of subquery)?
select count(1) cnt
from OF7.PETERV_TEST
where gender='F'
group by userId
Row f0_
1 14
2 1
3 7
4 18
5 1
6 4
7 2
8 2
expected result:
49
you can use:
SELECT sum(cnt)
FROM
(SELECT count(1) cnt
FROM OF7.PETERV_TEST
WHERE gender='F'
GROUP BY userId )
My simple database contains nodes of 'terms' and 'codes' linked to each other.
There are two types of relationships.
Relationships between 'terms' and 'codes' called :CODE and are undirected (or read in both directions equally).
Relationships between 'terms' called :NT (which means narrow term) and are directed.
I want to walk thru all the 'terms' from top to bottom and collect all the unique codes and count them.
This is my query:
MATCH (a)-[:NT*]->(b), (a)-[:CODE]-(c), (b)-[:CODE]-(d)
WHERE a.btqty = 0
RETURN a.termid AS termid, a.maxlen AS maxlen, COUNT(DISTINCT c.code) + COUNT(DISTINCT d.code) AS total, COLLECT(DISTINCT c.code) + COLLECT(DISTINCT d.code) AS codes
ORDER BY termid;
This is what I get:
termid maxlen total codes
22 2 3 ["S70","S43","S70"]
25 4 9 ["S20","S21","S54","S61","S63","S63","S21","S61","S54"]
26 2 9 ["S99","S98","S29","S13","S13","S20","S29","S14","S15"]
68 5 13 ["S38","S11","S12","S11","S12","S38","S37","S21","S36","S22","S98","S63","S58"]
123 2 3 ["S38","S12","S12"]
154 2 2 ["S58","S58"]
155 4 3 ["S63","S62","S63"]
159 2 2 ["S36","S36"]
...
I need to get rid of duplicates in collection and count them properly like this:
termid maxlen total codes
22 2 2 ["S43","S70"]
25 4 5 ["S20","S21","S54","S61","S63"]
26 2 7 ["S99","S98","S29","S13","S20","S14","S15"]
68 5 10 ["S38","S11","S12","S37","S21","S36","S22","S98","S63","S58"]
123 2 2 ["S38","S12"]
154 2 1 ["S58"]
155 4 2 ["S63","S62"]
159 2 1 ["S36"]
...
I think this is something about REDUCE function to apply but I do not know how to use it.
Thank you for your help!
You're right, this can be solved using REDUCE. Inside the reduce you need to check if the current element already exists in the accumulator and conditionally amend it:
MATCH (a)-[:NT*]->(b), (a)-[:CODE]-(c), (b)-[:CODE]-(d)
WHERE a.btqty = 0
WITH a.termid AS termid, a.maxlen AS maxlen,
REDUCE(uniqueCodes=[],
x in COLLECT(DISTINCT c.code) + COLLECT(DISTINCT d.code) |
CASE WHEN x IN uniqueCodes THEN uniqueCodes ELSE uniqueCodes+x END
) AS codes
ORDER BY termid
RETURN termid, maxlen, count(codes) as total, codes
I am hoping to get some help on a view which needs to be pivoted, I am not sure though.
View is in following format:
CASE CASE_ORDER MANAGER MONTHLY_CASES FISCAL_CASES
case_1 1 John 15 84
case_1 1 Jeff 10 80
case_2 2 John 20 90
case_2 2 Jeff 13 65
case_3 3 John 7 72
case_3 3 Jeff 17 70
My final chart should look like the following:
CASE CASE_ORDER JOHN_CURR_MONTH JOHN_FY JOHN_CURR_MONTH JOHN_FY
case_1 1 15 84 10 80
case_2 2 20 90 13 65
case_3 3 7 72 17 70
My problem is that managers can change and so does the number of managers from month to month,
so I can't hard code their names (ie. 'mgr1' and 'mgr2') and use DECODE. It has to be dynamic...
Thanks for your suggestion, I figured it out. In fact there is a similar answer in tom kyte's blog (http://www.oracle.com/technetwork/issue-archive/2012/12-jul/o42asktom-1653097.html) which I modified for my purpose. Here it is:
CREATE OR REPLACE PROCEDURE dynamic_pivot_proc ( p_cursor IN OUT SYS_REFCURSOR )
AS
l_query LONG := 'SELECT case_order, case';
BEGIN
FOR x IN (SELECT DISTINCT manager FROM test_table ORDER BY 1 )
LOOP
l_query := l_query ||
REPLACE( q'|, MAX(DECODE(manager,'$X$',monthly_total)) $X$_current_month|',
'$X$', dbms_assert.simple_sql_name(x.manager) ) ||
REPLACE( q'|, MAX(DECODE(manager,'$X$',fiscal_total)) $X$_fy|',
'$X$', dbms_assert.simple_sql_name(x.manager) );
END LOOP;
l_query := l_query || ' FROM test_table
GROUP BY case_order, case
ORDER BY case_order ';
OPEN p_cursor FOR l_query;
END;
SQL> variable x refcursor;
SQL> exec dynamic_pivot_proc( :x );
SQL> print x
CASE CASE_ORDER JEFF_CURRENT_MONTH JEFF_FY JOHN_CURRENT_MONTH JOHN_FY
1 case_1 10 80 15 84
2 case_2 13 65 20 90
3 case_3 17 70 7 72
Now the thing is instead of printing the result I want to store it in a view. How do I achieve that? I tried to modify the line
l_query LONG := 'SELECT case_order, case';
with
l_query LONG := 'CREATE OR REPLACE VIEW SELECT case_order, case';
Needless to say that it did not work because CREATE OR REPLACE is a DDL statement, so some how I have to use EXECUTE IMMEDIATE.
Any suggestion? Thanks in advance.