how to generate a query in SQL SERVER 2005 which gives output like Matrix? - sql-server-2005

H i have column which consists of 32 rows. like
ColumnA
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
while retrieving i want (4 X 8) means 4 columns 8 Rows.The Result should be like this
A B C D
1 9 17 25
2 10 18 26
3 11 19 27
4 12 20 28
5 13 21 29
6 14 22 30
7 15 23 31
8 16 24 32
Give me an Idea.

Something like this using CTE and row_number():
Fiddle demo
declare #numRows int = 8
;with cte as (
select columnA X, row_number() over (order by columnA) rn
from Table1
)
select c1.x A, c2.x B, c3.x C, c4.x D
from cte c1
left join cte c2 on c1.rn = c2.rn-#numRows
left join cte c3 on c1.rn = c3.rn-(#numRows * 2)
left join cte c4 on c1.rn = c4.rn-(#numRows * 3)
where c1.rn <= #numRows
results:
| A | B | C | D |
|---|----|----|----|
| 1 | 9 | 17 | 25 |
| 2 | 10 | 18 | 26 |
| 3 | 11 | 19 | 27 |
| 4 | 12 | 20 | 28 |
| 5 | 13 | 21 | 29 |
| 6 | 14 | 22 | 30 |
| 7 | 15 | 23 | 31 |
| 8 | 16 | 24 | 32 |

I can't see how to do it with a pivot given the lack of extra columns in the query making aggregation difficult. If you do have other columns then pivot would be less code consuming; but I'm not a pivot expert. You can do it easily enough with a few joins … used my tally table to generate the list of integers
SELECT
aa.StaticInteger as A,
bb.StaticInteger as B,
cc.StaticInteger as C,
dd.StaticInteger as D
FROM
tblTally aa
LEFT OUTER JOIN
(
SELECT
StaticInteger
FROM
tblTally
WHERE
StaticInteger BETWEEN 9 AND 16
) bb
ON
aa.StaticInteger = bb.StaticInteger - 8
LEFT OUTER JOIN
(
SELECT
StaticInteger
FROM
tblTally
WHERE
StaticInteger BETWEEN 17 AND 24
) cc
ON
bb.StaticInteger = cc.StaticInteger - 8
LEFT OUTER JOIN
(
SELECT
StaticInteger
FROM
tblTally
WHERE
StaticInteger BETWEEN 25 AND 32
) dd
ON
cc.StaticInteger = dd.StaticInteger - 8
WHERE
aa.StaticInteger BETWEEN 1 AND 8
Returns
A B C D
1 9 17 25
2 10 18 26
3 11 19 27
4 12 20 28
5 13 21 29
6 14 22 30
7 15 23 31
8 16 24 32

Related

RANK data by value in the column

I'd like to divide the data into separate groups (chunks) based on the value in the column. If the value increase above certain threshold, the value in the "group" should increase by 1.
This would be easy to achieve in MySQL, by doing CASE WHEN #val > 30 THEN #row_no + 1 ELSE #row_no END however I am using Amazon Redshift where this is not allowed.
Sample fiddle: http://sqlfiddle.com/#!15/00b3aa/6
Suggested output:
ID
Value
Group
1
11
1
2
11
1
3
22
1
4
11
1
5
35
2
6
11
2
7
11
2
8
11
2
9
66
3
10
11
3
A cumulative sum should do what you want:
SELECT *, sum((val>=30)::INTEGER) OVER (ORDER BY id BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW) FROM mydata ORDER BY id;
id | val | sum
----+-----+-----
1 | 11 | 0
2 | 11 | 0
3 | 22 | 0
4 | 11 | 0
5 | 35 | 1
6 | 11 | 1
7 | 11 | 1
8 | 11 | 1
9 | 66 | 2
10 | 11 | 2

expand oracle table fields linearly

I have the following table in oracle:
ID field_1 field_2
1 1-5 1-5
1 20-30 55-65
2 1-8 10-17
2 66-72 80-86
I need to convert this table to the following format where field_1 and field_2 must be matched linearly:
ID field_1 field_2
1 1 1
1 2 2
1 3 3
1 4 4
1 5 5
1 20 55
1 21 56
1 22 57
1 23 58
1 24 59
1 25 60
1 26 61
1 27 62
1 28 63
1 29 64
1 30 65
2 1 10
2 2 11
2 3 12
2 4 13
2 5 14
2 6 15
2 7 16
2 8 17
2 66 80
2 67 81
2 68 82
2 69 83
2 70 84
2 71 85
2 72 86
what is the easiest and fastest way to accomplish this, knowing that the original table contains thousands of records
The lateral clause, used below, is available since Oracle 12.1. For older versions, a connect by hierarchical query is still probably the fastest, but it will need to be written with a bit more care (and it will be slower than using connect by in a lateral join).
Of course, the big assumption is that the inputs are always in the form number-dash-number, and that the difference between the upper and the lower bound is the same in the two columns, for each row. I am not even attempting to check for that.
select t.id, l.field_1, l.field_2
from mytable t,
lateral (select to_number(substr(field_1, 1, instr(field_1, '-') - 1))
+ level - 1 as field_1,
to_number(substr(field_2, 1, instr(field_2, '-') - 1))
+ level - 1 as field_2
from dual
connect by level <=
to_number(substr(field_1, instr(field_1, '-') + 1))
- to_number(substr(field_1, 1, instr(field_1, '-') - 1)) + 1
) l
;
One option uses a recursive query. Starting 11gR2, Oracle supports standard recursive common table expressions, so you can do:
with cte(id, field_1, field_2, max_field_1, max_field_2) as (
select
id,
to_number(regexp_substr(field_1, '^\d+')),
to_number(regexp_substr(field_2, '^\d+')),
to_number(regexp_substr(field_1, '\d+$')),
to_number(regexp_substr(field_2, '\d+$'))
from mytable
union all
select
id,
field_1 + 1,
field_2 + 1,
max_field_1,
max_field_2
from cte
where field_1 < max_field_1
)
select id, field_1, field_2 from cte order by id, field_1
This assumes that intervals on the same row have always the same length, as showned in your sample data. If that's not the case, you would to explain how you want to handle that.
Demo on DB Fiddle:
ID | FIELD_1 | FIELD_2
-: | ------: | ------:
1 | 1 | 1
1 | 2 | 2
1 | 3 | 3
1 | 4 | 4
1 | 5 | 5
1 | 20 | 55
1 | 21 | 56
1 | 22 | 57
1 | 23 | 58
1 | 24 | 59
1 | 25 | 60
1 | 26 | 61
1 | 27 | 62
1 | 28 | 63
1 | 29 | 64
1 | 30 | 65
2 | 1 | 10
2 | 2 | 11
2 | 3 | 12
2 | 4 | 13
2 | 5 | 14
2 | 6 | 15
2 | 7 | 16
2 | 8 | 17
2 | 66 | 80
2 | 67 | 81
2 | 68 | 82
2 | 69 | 83
2 | 70 | 84
2 | 71 | 85
2 | 72 | 86
You can use the cross join with generated values as follows:
SELECT ID,
to_number(regexp_substr(field_1, '[0-9]+',1,1)) + column_value - 1 AS FIELD_1,
to_number(regexp_substr(field_2, '[0-9]+',1,1)) + column_value - 1 AS FIELD_2
FROM your_table
cross join
table(cast(multiset(select level from dual
connect by level <=
to_number(regexp_substr(field_1, '[0-9]+',1,2))
- to_number(regexp_substr(field_1, '[0-9]+',1,1))
+ 1
) as sys.odcinumberlist))
ORDER BY 1,2

SQL query for output [closed]

Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 3 years ago.
Improve this question
I have two tables T1 with columns Id. It has 5 values
1
2
3
4
5
Table T2 has 3 columns WeekNo, Id (same as first table) and count and the data is like:
40 1 10
40 2 11
41 1 13
41 2 12
41 3 14
42 1 16
42 2 15
42 3 17
42 4 18
42 5 19
I am trying to write one query which will give output like:
40 1 10
40 2 11
40 3 0
40 4 0
40 5 0
41 1 13
41 2 12
41 3 14
41 4 0
41 5 0
42 1 16
42 2 15..
Use a partitioned outer join:
SELECT t2.weekno,
t1.id,
COALESCE( t2.cnt, 0 ) AS cnt
FROM T1
LEFT OUTER JOIN T2
PARTITION BY ( T2.weekno )
ON (T1.id = T2.id);
outputs:
WEEKNO | ID | CNT
-----: | -: | --:
40 | 1 | 10
40 | 2 | 11
40 | 3 | 0
40 | 4 | 0
40 | 5 | 0
41 | 1 | 13
41 | 2 | 12
41 | 3 | 14
41 | 4 | 0
41 | 5 | 0
42 | 1 | 16
42 | 2 | 15
42 | 3 | 17
42 | 4 | 18
42 | 5 | 19
db<>fiddle here
In standard SQL, you would generate the rows and then left join the values:
select w.weekno, t1.id, coalesce(t2.cnt, 0)
from (select distinct weekno from t2) w cross join
t1 left join
t2
on t2.weekno = w.weekno and t2.id = t.id;
I assume the partition by clause has some superior performance compared to this. It is an Oracle-only feature.

Select pair where value of other column is equal

How do I select a pair (number, number) where tabid is equal for two numbers from the following table (i.e: number 7 and 11 have the same tabid):
tabid | number
---------+--------
1 | 6
1 | 6
2 | 7
3 | 8
4 | 8
5 | 10
5 | 11
6 | 12
6 | 11
5 | 6
4 | 7
3 | 8
2 | 11
The result of this should be:
number | number
---------+--------
7 | 11
7 | 8
10 | 11
11 | 12
6 | 10
6 | 11
Is this what you're looking for:
select
t1.number, t2.number
from t t1, t t2
where t1.tabid = t2.tabid
and t1.number < t2.number;
produces:
NUMBER NUMBER
---------- ----------
6 10
6 11
7 8
7 11
10 11
11 12
Use array_agg to concatenate the tabid's into an array. Thereafter self join this cte to check if one array is an overlap of the other using the array operator &&.
with concatenated as (
select array_agg(tabid) as arr_tab, num
from t
group by num
)
select c1.num,c2.num
from concatenated c1
join concatenated c2 on c1.num < c2.num
where c2.arr_tab && c1.arr_tab
order by 1,2
Sample Demo

How to write the SQL query?

Suppose I have the following table, How can I write the SQL query to find a set of results which are the minimum c for each b? for example, I want (7, 45) and (16, 69) for the following table.
a | b | c
-----+--------+----
3 | 7 | 53
2 | 7 | 49
1 | 7 | 45
5 | 7 | 61
13 | 16 | 69
15 | 16 | 77
6 | 7 | 65
4 | 7 | 57
14 | 16 | 73
Just use GROUP BY:
SELECT b, MIN(c)
FROM yourTable
GROUP BY b
You can do this using distinct on in Postgres:
select distinct on (b) b, c
from t
order by b, c asc;
An alternative is group by:
select b, min(c)
from t
group by b;
You can try both and see which is faster.