split 1 column in 5 columns - sql

I have a relatively simple problem (I think), but I can not get my head around it. I have a single column with 200 records. The values of the rows are a list of numbers 1-200 (No duplicates). I would like to organize the numbers in 5 columns with the data sorted horizontally (Ascending A-Z). Example:
Original table:
Column1
1
2
3
4
5
6
7
8
...and so on to 200
The view result should look like this:
|Col1|Col2|Col3|Col4|Col5|
1 2 3 4 5
6 7 8 9 10
11 12 ...an so on to 200
I looked into PIVOTING but I don't think it will work.

We can try a pivot query where the group is defined as the column minus one, divided by 5. This places the first five records into the first group/row, the next five into the second group/row, and so on. Then, we pivot on each Column1 % 5 value to determine into which of the five columns each value will go.
SELECT
MAX(CASE WHEN Column1 % 5 = 1 THEN Column1 END) AS Col1,
MAX(CASE WHEN Column1 % 5 = 2 THEN Column1 END) AS Col2,
MAX(CASE WHEN Column1 % 5 = 3 THEN Column1 END) AS Col3,
MAX(CASE WHEN Column1 % 5 = 4 THEN Column1 END) AS Col4,
MAX(CASE WHEN Column1 % 5 = 0 THEN Column1 END) AS Col5
FROM yourTable
GROUP BY
(Column1 - 1) / 5;
Demo

Related

SQL Server - Pivoting rows into fixed number of columns with columns sorted rather than rows

I am using SQL server 2012 and I am trying to 'pivot' a table output so that I can reformat a results table for display to the user.
The easiest way to describe it is with an example:
Input
MyCol
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
Output
Col1 Col2 Col3
1 7 13
2 8 14
3 9 15
4 10 16
5 11 17
6 12
I thought about using temporary tables to store the relevant row values and then query those but it seems a little long winded. There has to be a slick way to achieve this beyond my expertise.
Use window functions to enumerate and count the rows and then some arithmetic to assign the position:
select (case when mycol < ceil(cnt / 3) then mycol end) as col1,
(case when mycol >= ceil(cnt / 3) and mycol < 2*ceil(cnt / 3) then mycol end) as col2,
(case when mycol >= 2*ceil(cnt / 3) then mycol end) as col3
from (select t.*,
row_number() over (order by mycol) - 1 as seqnum,
count(*) over () as cnt
from t
) t
group by mycol % ceil(cnt / 3)

SQL: Counting occurrences based on the value of 2 fields

I am looking for an efficient way to count occurrences of a combination of 2 field values.
Here is my table:
field1 field2
1 a
1 b
1 b
2 a
2 b
Field 2 has a predefined set of possible values (let's say "a" and "b").
I need to add columns that count how many rows there are for the current field1 value for each possible value in field 2 (e.g. for field1=1 there is 1 occurrence of field2="a" and 2 occurrences of field2="b")
Output would be something like:
field1 field2 field2_a_count field2_b_count
1 a 1 2
1 b 1 2
1 b 1 2
2 a 1 1
2 b 1 1
Sub-queries do the job but are slow. I could not figure our a solution with windowing functions, which are more efficient.
SELECT
field1,
field2,
(SELECT COUNT(*) FROM table WHERE field1=t.field1 AND field2='a') AS field2_a_count,
(SELECT COUNT(*) FROM table WHERE field1=t.field1 AND field2='b') AS field2_b_count,
FROM table t
Any way I can improve the efficiency?
You can do this calculation using window functions:
SELECT field1, field2,
SUM(CASE WHEN field2 = 'a' THEN 1 ELSE 0 END) OVER (PARTITION BY field1) as field2_a_count,
SUM(CASE WHEN field2 = 'b' THEN 1 ELSE 0 END) OVER (PARTITION BY field1) as field2_b_count
FROM table t;

Update table using rownum

I have a table that I would like to update in oracle. It's okay to assume that the rownum are in sequential order from 1 through 7
Table Have
1
2
3
4
4
4
4
Table Want
1
2
3
4
5
6
7
It seems that you want to have unique sequential numbers in that column.
If you don't care much about conditions, you could even
update have set col1 = rownum;
If I get you right you need something like UPDATE all your duplicated (in your case value = 4) rows by adding (rownum -1).
See example below.
create table have as
select case when rownum <= 4 then rownum else 4 end col1 from dual connect by level <= 7;
select col1 from have order by col1;
COL1
----------
1
2
3
4
4
4
4
update have
set col1 = col1 + rownum -1 where col1 = 4;
select col1 from have order by col1;
COL1
----------
1
2
3
4
5
6
7

T-Sql: Select Rows where at least two fields matches condition

I've got a table, let's call it values with a primary key and five integer fields, like this:
id val1 val2 val3 val4 val5
1 4 3 4 5 3
2 2 3 2 2 2
3 5 4 1 3 3
4 1 4 3 4 4
Now I need to select all rows where at least any two of the five value fields got the value 4. So the result set should contain the first row (id=1) and the last row (id=4).
I started with a simple OR condition but there are too many combinations. Then I tried a sub-select with HAVING and COUNT but no success.
Any Ideas how to solve this?
You can use VALUES to construct an inline table containing your fields. Then query this table to get rows having at least two fields equal to 4:
SELECT *
FROM mytable
CROSS APPLY (
SELECT COUNT(*) AS cnt
FROM (VALUES (val1), (val2), (val3), (val4), (val5)) AS t(v)
WHERE t.v = 4) AS x
WHERE x.cnt >= 2
Demo here
Although cross apply is fast, it might be marginally faster to simply use case:
select t.*
from t
where ((case when val1 = 4 then 1 else 0 end) +
(case when val2 = 4 then 1 else 0 end) +
(case when val3 = 4 then 1 else 0 end) +
(case when val4 = 4 then 1 else 0 end) +
(case when val5 = 4 then 1 else 0 end)
) >= 2;
I will also note that case is ANSI standard SQL and available in basically every database.
This is trivial to solve if your data is normalized - so lets use UNPIVOT to normalize the data and then solve it:
declare #t table (id int not null, val1 int not null, val2 int not null,
val3 int not null, val4 int not null, val5 int not null)
insert into #t(id,val1,val2,val3,val4,val5) values
(1,4,3,4,5,3),
(2,2,3,2,2,2),
(3,5,4,1,3,3),
(4,1,4,3,4,4)
select
id
from
#t t
unpivot
(valness for colness in (val1,val2,val3,val4,val5)) r
group by id
having SUM(CASE WHEN valness=4 THEN 1 ELSE 0 END) >= 2
Results:
id
-------
1
4
Of course, you can probably come up with better names than valness and colness that describes what these pieces of data (the numbers being stored and the numbers embedded in the column names) actually are.

How to check Oracle column values are all the same for a specific ID?

I am trying to figure out the best way to determine, for a specific ID within an Oracle 11g table that has 5 columns and say 100 rows against this ID, if all the column values are the same for these five columns.
For example:
Table Name: TABLE_DATA
Columns:
TD_ID ID COL1 COL2 COL3 COL4 COL5
-----------------------------------------------------------------------
1 1 1 0 3 2 0
2 1 1 0 3 2 0
3 1 1 0 3 2 0
4 1 1 0 3 2 0
5 1 1 0 3 2 0
6 1 1 0 3 2 0
So based on the above example which is just showing 6 rows for now against the ID:1, I want to check that for all COL1, COL2, COL3, COL4 and COL5 values where ID = 1, tell me if all the values are the same from the very first row right down to the last – if so, then return ‘Y’ else return ‘N’.
Given the above example, the result would be ‘Y’ but for instance, if TD_ID = 5 and COL3 = 4 then the result would be ‘N’, as all the column values are not the same, i.e.:
TD_ID ID COL1 COL2 COL3 COL4 COL5
-----------------------------------------------------------------------
1 1 1 0 3 2 0
2 1 1 0 3 2 0
3 1 1 0 3 2 0
4 1 1 0 3 2 0
5 1 1 0 4 2 0
6 1 1 0 3 2 0
I’m just not sure what the fastest approach to determine this is, as the table I am looking at may have more than 2000 rows within the table for a specific ID.
You may also try this :
Select ID
, case when count(distinct COL1 || COL2 || COL3 || COL4 || COL5) > 1
then 'N'
else 'Y' end RESULT
From TABLE_DATA
Group by id;
In this way you group by id and counts how many distinct combination are there.
If only 1 , so all the rows have the same set of values, otherwise it don't.
See if the following is fast enough for you:
SELECT ID, CASE WHEN COUNT(*) > 1 THEN 'No' ELSE 'Yes' END As "Result"
FROM (SELECT DISTINCT ID, COL1, COL2, COL3, COL4, COL5
FROM Table_Data) dist
GROUP BY ID
Here's a little query, you might wanna try out (eventually, you just could try figuring out a better MINUS statement for you):
SELECT
CASE
WHEN ( -- select count of records from a subquery
SELECT
COUNT(1)
FROM
( -- select all rows where id = 1
SELECT
td.col1
,td.col2
,td.col3
,td.col4
,td.col5
FROM
table_data td
WHERE
td.id = 1
MINUS -- substract the first row of the table with id = 1
SELECT
td.col1
,td.col2
,td.col3
,td.col4
,td.col5
FROM
table_data td
WHERE
td.id = 1
AND ROWNUM = 1
)
) = 0 -- check if subquery's count equals 0
AND EXISTS ( -- and exists at least 1 row in the table with id = 1
SELECT
1
FROM
table_data td
WHERE
td.id = 1
AND ROWNUM = 1
) THEN 'Y'
ELSE 'N'
END AS equal
FROM
dual