How get result as:
Get all from table_1 where ORACLE (ID = 10)
ID DAY ID2
---------------
1 1 10
2 2 10
3 3 10
4 4 10
Structure:
Create table table_1 (
id number primary key,
day_1 number,
day_2 number,
day_3 number,
day_4 number,
day_5 number
)
Insert into table_1 (id,day_1,day_2,day_3,day_4,day_5) values (1,10,null,null,null,null);
Insert into table_1 (id,day_1,day_2,day_3,day_4,day_5) values (2,20,10,20,null,null);
Insert into table_1 (id,day_1,day_2,day_3,day_4,day_5) values (3,null,null,10,null,null);
Insert into table_1 (id,day_1,day_2,day_3,day_4,day_5) values (4,null,null,null,10,null);
Insert into table_1 (id,day_1,day_2,day_3,day_4,day_5) values (5,30,null,null,null,null);
--Note
10 - ORACLE
20 - MSSQL
30 - MYSQL
Use UNPIVOT:
SELECT *
FROM table_1
UNPIVOT (
id2 FOR day IN (
day_1 AS 1,
day_2 AS 2,
day_3 AS 3,
day_4 AS 4,
day_5 AS 5
)
)
WHERE id2 = 10;
Which, for your sample data, outputs:
ID
DAY
ID2
1
1
10
2
2
10
3
3
10
4
4
10
db<>fiddle here
Related
I have the following table:
RowID Column1 Column2
1 3 2
2 5 2
3 2 9
4 5 NULL
5 8 NULL
6 9 3
7 1 NULL
I need first row of Column1 to Sum every time there is a NULL value in Column2. And it would continue the logic down the rows.
So, the result should look like:
RowID Column1 Column2
1 3 2
2 5 2
3 15 9
4 5 NULL
5 8 NULL
6 10 3
7 1 NULL
Notice Row 3 summed 2+5+8 =15 and Row 6 summed 9+1 =10. So, basically the row prior to Null value in Column2 summed the values in column1 until there was no more NULL values in column2. Then it resumed in row 6 where the next value was NULL.
This will do it. I have set up the data in a table variable for demo.
declare #t table(RowID int, C1 int, C2 int)
insert #t values (1, 3, 2)
,(2, 5, 2)
,(3, 2, 9)
,(4, 5, NULL)
,(5, 8, NULL)
,(6, 9, 3)
,(7, 1, NULL)
select RowID, sum(C1), max(C2)
from (
select RowID, C1, C2 from #t
union all
select T1.RowID, T2.C1, null
from #t t1
join #t t2 on t2.RowID>t1.RowID and t2.C2 is null
and not exists(
select * from #t t3
where t3.RowID>t1.RowID and t3.c2 is not null and t3.RowID<t2.RowID
)
where T1.C2 is not null
) q group by RowID
Result:
RowID C1 C2
1 3 2
2 5 2
3 15 9
4 5 NULL
5 8 NULL
6 10 3
7 1 NULL
I got it. You need to look at the rows in reverse order, assigning the NULL values to the value before them.
The idea is to assign a group to the rows to sum. This is the number of non-NULL values following the row. With this, you can then use a window function to aggregate:
select t.*,
(case when c2 is null then c1
else sum(c1) over (partition by grp)
end) as new_c1
from (select t.*, count(c2) over (order by rowid rows between 1 following and unbounded following) as grp
from t
) t
order by rowid;
Here is a db<>fiddle.
I'm trying to find similar values from an array -not just one, but a group of them, while the sum of their element-wise differences is to be the lowest possible value
EXAMPLE:
0
2
4
6
8
9
11
15
16
19
pick 5 numbers
RESULT:
4
6
8
9
11
or
2
4
6
8
9
Where the sum of the element-wise difference of both groups is 7.
The problem is I need to select such group of 1500 numbers from an array of 2927 numbers and I'm not sure if algorithm which takes groups of 0-1500 (indexes)numbers and sums the differences, then goes i+1 until it reaches the 1427-2927 group is effective (finally I would check the smallest sum and which group it belongs to).
Note, that numbers are sorted (doesn't matter if ASC or DESC) and I'm trying to do that using PostgreSQL.
Thanks in advance.
SQL Fiddle
PostgreSQL 9.3 Schema Setup:
A small dataset of random data:
CREATE TABLE test (
id INT,
population INT
);
INSERT INTO TEST VALUES ( 1, 12 );
INSERT INTO TEST VALUES ( 2, 11 );
INSERT INTO TEST VALUES ( 3, 14 );
INSERT INTO TEST VALUES ( 4, 6 );
INSERT INTO TEST VALUES ( 5, 7 );
INSERT INTO TEST VALUES ( 6, 7 );
INSERT INTO TEST VALUES ( 7, 1 );
INSERT INTO TEST VALUES ( 8, 15 );
INSERT INTO TEST VALUES ( 9, 14 );
INSERT INTO TEST VALUES ( 10, 14 );
INSERT INTO TEST VALUES ( 11, 15 );
INSERT INTO TEST VALUES ( 12, 12 );
INSERT INTO TEST VALUES ( 13, 11 );
INSERT INTO TEST VALUES ( 14, 3 );
INSERT INTO TEST VALUES ( 15, 8 );
INSERT INTO TEST VALUES ( 16, 1 );
INSERT INTO TEST VALUES ( 17, 1 );
INSERT INTO TEST VALUES ( 18, 2 );
INSERT INTO TEST VALUES ( 19, 3 );
INSERT INTO TEST VALUES ( 20, 5 );
Query 1:
WITH ordered_sums AS (
SELECT ID,
POPULATION,
ROW_NUMBER() OVER ( ORDER BY POPULATION ) AS RN,
POPULATION - LAG(POPULATION,4) OVER ( ORDER BY POPULATION ) AS DIFFERENCE
FROM test
), minimum_rn AS (
SELECT DISTINCT FIRST_VALUE( RN ) OVER wnd AS optimal_rn
FROM ordered_sums
WINDOW wnd AS ( ORDER BY DIFFERENCE )
)
SELECT ID,
POPULATION
FROM ordered_sums o
INNER JOIN
minimum_rn m
ON ( o.RN BETWEEN m.OPTIMAL_RN - 4 AND m.OPTIMAL_RN )
Results:
| id | population |
|----|------------|
| 10 | 14 |
| 9 | 14 |
| 3 | 14 |
| 11 | 15 |
| 8 | 15 |
The query above will select 5 rows - to change it to select N rows then change the 4s in the LAG function and in the last line to N-1.
Assume the list is a[1], a[2], ..., a[N+M].
Calculate the minimal value of a[i+M-1]-a[i] for i=1 to N+1.
The value(s) of i for which the minimal value is reached are the first indices of M consecutive numbers in which the sum of the element-wise difference is minimal.
One key observation to understand this algorithm is that the "sum of the element-wise differences" of a sequence of sorted integers is simply the difference between the first and last element. E.g. for 4 6 8 9 11 it is 11-4=7.
This solution should work. Row_number() to get the order. self-Join on +1499, then order by the difference of sizes in the pair.
DECLARE #cities TABLE (
city VARCHAR(512)
,size INT
,rownum INT
)
INSERT INTO #cities
SELECT *
,row_number() OVER (
ORDER BY size
) rownum
FROM
rawdata
SELECT *
,d.size - c.size difference
FROM #cities c
INNER JOIN #cities d ON c.rownum + 1499 = d.rownum
WHERE c.rownum <=2927-1499
ORDER BY d.size - c.size
I have table with below data :
Block_id Value
1 5
2 5
3 5
4 0
5 0
6 4
7 4
And I have to write query that give me below output :
Block_id
1-3
6-7
How to achieve this with pl/sql in Oracle 11g ?
you can do something like:
SQL> select * from data order by block_id;
BLOCK_ID VALUE
---------- ----------
1 5
2 5
3 5
4 0
5 0
6 4
7 4
9 5
10 5
12 2
SQL> select min(block_id) || '-' || max(block_id) block_range, value
2 from (select block_id, value, max(grp) over (partition by value order by block_id) grp
3 from (select block_id, value,
4 case
5 when lag(block_id) over (partition by value order by block_id) < block_id - 1
6 then
7 row_number() over (partition by value order by block_id)
8 when row_number() over (partition by value order by block_id) = 1 then 1
9 else null
10 end grp
11 from data
12 where value != 0))
13 group by value, grp
14 order by min(block_id);
BLOCK_RANG VALUE
---------- ----------
1-3 5
6-7 4
9-10 5
12-12 2
You do not need PL/SQL to do this, a simple query will do:
CREATE TABLE test(
a INTEGER,
b INTEGER
);
INSERT INTO test VALUES (1, 5);
INSERT INTO test VALUES (2, 5);
INSERT INTO test VALUES (3, 5);
INSERT INTO test VALUES (4, 0);
INSERT INTO test VALUES (5, 0);
INSERT INTO test VALUES (6, 4);
INSERT INTO test VALUES (7, 4);
select min(a) || '-' || max(a) from test group by b order by 1;
An alternative approach is to use aggregate functions:
select distinct
min(block_id) over (partition by value) || '-' ||
max(block_id) over (partition by value)
from whatever_your_table_is_called
where value > 0;
In Oracle, suppose I have a query that returns the following list:
ID Sequence#
12 1
15 3
25 5
All I know in this case is the ID of some row (let's suppose 12), I need to return the ID of a row with the next sequence number which in this case is 3 (id = 15)
How can I do it? I know there's a Oracle function lead, but I wasn't able to successfully impement is.
Yes, you can use lead function to get the next value. Here is an example of how it can be done.
-- sample of data from your question
SQL> with t1(ID, Sequence#) as
2 (
3 select 12, 1 from dual union all
4 select 15, 3 from dual union all
5 select 25, 5 from dual
6 )
7 select *
8 from (select id
9 , sequence#
10 , lead(sequence#) over(order by id) next_sequence#
11 , lead(id) over(order by id) next_id#
12 from t1
13 )
14 where id = 12
15 ;
ID SEQUENCE# NEXT_SEQUENCE# NEXT_ID#
---------- ---------- -------------- ----------
12 1 3 15
SELECT * FROM table1 where ID in (SELECT min(ID) FROM table1 WHERE ID > 12)
Select sequence from my_ table where id=(select min(id) from my_table where sequence> 1)
Replace (1) in the above query with any value that you are searching for its next
I have the following table:
ID | X
1 | 1
2 | 2
3 | 5
4 | 6
5 | 7
6 | 9
I need to enumerate groups of rows in such way that if row i and i-1 differ in column X by less than 2 they should have the same group number N. See example below.
ID | X | N
1 | 1 | 1
2 | 2 | 1
3 | 5 | 2
4 | 6 | 2
5 | 7 | 2
6 | 9 | 3
Note that rows X(2)-X(1)=1 so they are grouped in the first group. Than X(3)-X(2)=3 so the 3rd row goes to 2nd group with 3rd and 4th row. X(6)-X(5)=2 so 6th row is in the 3rd group.
Can anybody help me with writing SQL query that will return the second table?
This should do it:
select id, x, sum(new_group) over (order by id) as group_no
from
( select id, x, case when x-prev_x = 1 then 0 else 1 end new_group
from
( select id, x, lag(x) over (order by id) prev_x
from mytable
)
);
I get the correct answer for your data with that query.
SQL> create table mytable (id,x)
2 as
3 select 1, 1 from dual union all
4 select 2, 2 from dual union all
5 select 3, 5 from dual union all
6 select 4, 6 from dual union all
7 select 5, 7 from dual union all
8 select 6, 9 from dual
9 /
Table created.
SQL> select id
2 , x
3 , sum(y) over (order by id) n
4 from ( select id
5 , x
6 , case x - lag(x) over (order by id)
7 when 1 then 0
8 else 1
9 end y
10 from mytable
11 )
12 order by id
13 /
ID X N
---------- ---------- ----------
1 1 1
2 2 1
3 5 2
4 6 2
5 7 2
6 9 3
6 rows selected.
Which is essentially the same as Tony's answer, only one inline view less.
Regards,
Rob.
Using basic operations only:
create table test(id int, x int);
insert into test values(1, 1), (2, 2), (3, 5), (4, 6), (5, 7), (6, 9);
create table temp as
select rownum() r, 0 min, x max
from test t
where not exists(select * from test t2 where t2.x = t.x + 1);
update temp t set min = select max + 1 from temp t2 where t2.r = t.r - 1;
update temp t set min = 0 where min is null;
select * from temp order by r;
select t.id, t.x, x.r from test t, temp x where t.x between x.min and x.max;
drop table test;
drop table temp;