pivot/unpivot statement - sql

Hi, having table like this
NR PROJECT RESULT
1 name1 234
1 name2 937
2 name1 3
2 name2 6
I'm trying to have results presented this way:
NR NAME1 NAME2
1 234 937
2 3 6
so the VALUES of the PROJECT column become headers presenting respective RES value while the same NR values are merged into a single row
help :)

If you're working with a fixed list of projects, you can use (as you've mention in the title of your question) a pivot.
http://www.oracle.com/technetwork/articles/sql/11g-pivot-097235.html
SELECT
*
FROM
yourTable
PIVOT
(
SUM(result)
FOR project IN ('name1' AS NAME1, 'name2' AS NAME2)
)
This would give the same results as from a "conditional aggregate".
SELECT
NR,
SUM(CASE WHEN PROJECT = 'name1' THEN result END) AS NAME1,
SUM(CASE WHEN PROJECT = 'name2' THEN result END) AS NAME2
FROM
yourTable
GROUP BY
NR
Examples : http://dbfiddle.uk/?rdbms=oracle_11.2&fiddle=19f31ce152f4f88c3d74e867016765d7

Related

Condition filtering SQL

I have a table
Table name - commands
id
name
status
group_id
id - number
name - string
status - 0 or 1
group_id - number
I need to sort as follows: for all elements with the same group_id I have to check if at least one has a status of 1, if so, then leave, if not, then remove such a group and so on for all group_id
I tried to do it through GROUP BY, and then using HAVING to remove unnecessary groups, but this way I don't get the whole table to be displayed or a query that does not work.
I think it should look like:
SELECT COUNT(*) FROM commands GROUP BY group_id HAVING *condition*
Please let me know if there are any other commands to use.
id
name
status
group_id
1
name1
0
1
2
name2
0
1
3
name3
0
2
4
name4
1
2
5
name5
1
2
6
name6
0
3
7
name7
1
4
Result:
id
name
status
group_id
3
name3
0
2
4
name4
1
2
5
name5
1
2
7
name7
1
4
In Postgres, that's a good spot to use a boolean window function:
select *
from (
select t.*, bool_or(status = 1) over(partition by group_id) has_status_1
from mytable t
) t
where has_status_1
bool_or checks if any row in the group satisfies its predicate ; we can use this information for filtering.
The upside is that the table is scanned only once, as opposed to the correlated subquery solution.
You may use EXISTS operator with a correlated subquery as the following:
SELECT id, name, status, group_id
FROM table_name T
WHERE EXISTS(SELECT 1 FROM table_name D WHERE D.group_id = T.group_id AND D.status=1)
ORDER BY id
See a demo.

bigquery - Combine row data with columns of unique data

can this scenario be accomplished with a single query?
read example table and transpose based on id each cat and value.
Existing Table would contain the columns and or null columns are created when
select is done (e.gl NULL Att1_Val1)
Example Table Existing Table
id name cat value ID Name Att1_Val1 Att2_Val1 Att3_Val1 Att4_Val1
1 name1 att1 1 1 Name1 1 2 3 Null
1 name1 att2 2 1 Name2 4 5 6 7
1 name1 att3 3
2 name2 att1 4
2 name2 att2 5
2 name2 att3 6
2 name2 att4 7
See snapshot for a Better view of tables
I resolved this for my real table structure (names in the example where changed and I also had a case statement. But this is the basic of how I solved.
Select id, Name, Att1, Att2, Att3, Att4
FROM (SELECT id, value, att FROM 'List_table' as Source_Table)
PIVOT
(MAX(Value) FOR att
IN ('Att1', 'Att2', 'Att3','Att4'))
AS Pivot_table

Select dynamic column based on value of another column?

Given the following table, I would like to dynamically select the Name1 or Name2 field based on the value of the WhichName column.
id Name1 Name2 WhichName SomeValue
1 Bob James 1 Blue
2 Steve 2 Horse
3 Fred 1 Radish
The results should look like this:
id Name SomeValue
1 Bob Blue
2 Steve Horse
3 Fred Radish
DBMS is Caché
You can do this with case:
select id,
(case when WhichName = 1 then Name1 else Name2 end) as Name,
SomeValue
from <table>;
Note: if your prefer Name1, unless it is NULL, then you can use COALESCE():
select id, coalesce(Name1, Name2) as Name, SomeValue
from <table>;

Aggregate rows based on ordered columns in SQL

I have a table with ordered columns by name, from:
Name from to code
name1 0 1 cal
name1 1 2 cal/top
name1 2 4 cal
name1 4 5 top
name1 5 6 cal
name2 0 3 top
name2 3 5 cal
name2 5 7 cal/top
where I want to aggregate them into a table based on code like CAL:
Name minFrom MaxTo
name1 0 4
name1 5 6
name2 3 7
I have tried this:
SELECT name, MIN(from) AS minfrom, MAX(to) AS maxto
FROM table1
GROUP BY name, code, From
HAVING code like "*CAL*"
ORDER BY name, From;
and searched for a like question on stackoverflow with no luck. I think I'll have to do a select subquery but I have no idea where to start... Please help! BTW I'm using postgresql...
You can identify the groups of similar records by using a difference of row numbers. This gives you a grouping column, which can then be used for aggregation:
select name, min(from) as minfrom, max(to) as maxto
from (select t.*,
(row_number() over (partition by name order by from) -
row_number() over (partition by name,
(case when code like 'col%' then 1 else 0 end)
order by from
)
) as grp
from table1 t
) t
where code not like 'col%'
group by grp, name;
Have you been able to reproduce without the need for a partition table? I think just dropping your having statement may make sense for a where statement.
SELECT name, MIN(from) AS minfrom, MAX(to) AS maxto
FROM table1
Where code like "*CAL*"
GROUP BY name, code, From
ORDER BY name, From;

Select multiple records as multiple columns in SQL

I have a table that look like this:
ID Name
-------
1 John
1 Mary
1 Jane
2 John
2 Mary
3 Jane
Knowing that every ID can only contain up to three names, I want to use a SELECT statement to turn this into the following:
ID Name1 Name2 Name3
--------------------
1 John Mary Jane
2 John Mary
3 Jane
Is there a way to do this in SQL?
If you know that there are at most three names, you can do this using conditional aggregation:
select id,
max(case when seqnum = 1 then name end) as name1,
max(case when seqnum = 2 then name end) as name2,
max(case when seqnum = 3 then name end) as name3
from (select t.*, row_number() over (partition by id order by name) as seqnum
from table t
) t
group by id;
With Oracle, you can use the PIVOT feature.
However, you'll need to RANK your rows first, over id-name pairs, and then you can do the pivot directive for (literally) the rank you just generated.
Pages to read:
http://www.oracle.com/technetwork/articles/sql/11g-pivot-097235.html
http://www.oracle-developer.net/display.php?id=506