Optimize rows to columns conversion - sql

I have a big Oracle table (around 40 million rows) that looks like this:
ID Name Question Answer Reason
3 Name1 1 Yes blah blah
3 Name1 2 No NA
3 Name1 3 No NA
3 Name1 4 Yes blah2
3 Name1 5 Yes null
3 Name1 6 Yes blah3
3 Name1 7 No null
6 Name2 1 Yes blah4444
6 Name2 2 No null
6 Name2 3 Yes blah3
6 Name2 4 NA blah5
6 Name2 5 Yes null
6 Name2 6 Yes blah6
6 Name2 7 NA null
I need one row per ID i.e. I will need to add columns for each question's answer (there are 7 questions per ID) and each question's reason. I need to make it look like this:
ID Name Q1 Q1-Reason Q2 Q2-Reason Q3 Q3-Reason etc.
3 Name1 Yes blah blah No null
6 Name2 Yes blah4444 No null
My query currently looks like this:
select
A.ID,A.NAME,B1.Q1,B1.Q1-REASON,B2.Q2,B2.Q2-REASON
from
TABLENAME A
inner join
(
select distinct C1.ID,C1.ANSWER as Q1,C1.REASON as Q1-REASON
from TABLENAME C1
where C1.QUESTION=1
) B1 on B1.ID=A.ID
inner join
(
select distinct C2.ID,C2.ANSWER as Q2,C2.REASON as Q2-REASON
from TABLENAME C2
where C2.QUESTION=2
) B2 on B2.ID=A.ID
...
...
However, as the table is huge, this is taking a VERY long time to retrieve the data. Could someone suggest ways to optimize this query?
I'm on Oracle 10g and SQLDeveloper 4.0.2.15

You could do this:
SELECT
TABLENAME.ID,
TABLENAME.Name,
MAX(CASE WHEN TABLENAME.Question=1 THEN TABLENAME.Answer ELSE NULL END) AS Q1,
MAX(CASE WHEN TABLENAME.Question=1 THEN TABLENAME.Reason ELSE NULL END) AS Q1_Reason,
MAX(CASE WHEN TABLENAME.Question=2 THEN TABLENAME.Answer ELSE NULL END) AS Q2,
MAX(CASE WHEN TABLENAME.Question=2 THEN TABLENAME.Reason ELSE NULL END) AS Q2_Reason,
MAX(CASE WHEN TABLENAME.Question=3 THEN TABLENAME.Answer ELSE NULL END) AS Q3,
MAX(CASE WHEN TABLENAME.Question=3 THEN TABLENAME.Reason ELSE NULL END) AS Q3_Reason
/*And so on*/
FROM
TABLENAME
GROUP BY
TABLENAME.ID,
TABLENAME.Name

Related

How to pivot/merge rows based on condition in BigQuery?

I have a table that looks like this:
record
name1
name2
to_merge
value1
value2
1
STEVE
null
false
30
null
2
JOHN
null
true
43
null
3
null
LAURA
true
null
66
4
JEN
null
false
18
null
I want this to be the output:
record
name1
name2
value1
value2
1
STEVE
null
30
null
2
JOHN
LAURA
43
66
3
JEN
null
18
null
This means I want to merge the rows with a TRUE value in the to_merge field. Any help is much appreciated!
Consider below
select * except(to_merge)
from your_table
where not to_merge
union all
select max(name1), max(name2),
max(value1), max(value2)
from your_table
where to_merge
if applied to data in your question - output is

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

Edit 2 rows into 2 columns in a single result SQL

I have the following table:
WorkID WorkDesc
--------------------
1 ABCD
2 DEFG
3 HIJK
then I've the following table as the detail of table one:
WorkDetailID WorkID WorkDetailDesc
-----------------------------------------
1 1 001
2 1 002
3 2 006
4 2 007
5 3 015
Each WorkID is always have maximum 2 records and minimum is 1.
I want to have the following result:
WorkID WorkDesc WorkDetailID1 WorkDetailID2
-------------------------------------------------------
1 ABCD 1 2
2 DEFG 3 4
3 HIJK 5 null
Does anyone have an idea how to do that?
Thank you.
You can use pivot. I prefer conditional aggregation. In either case, you need a column for the pivoting. row_number() to the rescue:
select t1.workid, t1.workdesc,
max(case when t2.seqnum = 1 then t2.workdetailid end) as workdetailid1,
max(case when t2.seqnum = 2 then t2.workdetailid end) as workdetailid2
from t1 join
(select t2.*,
row_number() over (partition by t2.workid order by t2.workdetailid) as seqnum
from t2
) t2
on t1.workid = t2.workid
group by t1.workid, t1.workdesc

Query for rows with specific string or null

I have the following tables, I need a query in Oracle SQL:
T1:
ID (PK)
1
2
3
4
5
6
7
8
T2:
Id T1-ID(FK) Value
1 1 apple
2 2 null
3 2 null
4 3 apple
5 3 null
6 4 apple
7 4 orange
8 4 null
9 5 orange
10 5 null
11 6 orange
12 6 apple
13 7 kiwi
14 8 mango
15 8 apple
16 8 null
how do I get the rows that have only apple or null or both. The query should not return any rows that have orange, kiwi, mango etc even if that ID has apple or null.
Output:
Id T1-ID(FK) Value
1 1 apple
2 2 null
3 2 null
4 3 apple
5 3 null
select t.*
from t2 t
where (t.value = 'apple' or t.value is null)
and not exists (select 1
from t2 x
where x.t1_id = t.t1_id
and x.value <> 'apple')
order by t.id;
SQLFiddle example: http://sqlfiddle.com/#!15/a9f28/1
Here is a solution using sub-query and GROUP_CONCAT.
SELECT *
FROM T2
WHERE `T1-ID` IN
(SELECT
`T1-ID`
FROM T2
GROUP BY `T1-ID`
HAVING 'apple' = GROUP_CONCAT(DISTINCT Value))

SQL Server: SELECT value with multiple criteria

Looking for a SQL solution to the following problem
Return USER and NUMBER combination WHERE PRIORITY = MIN(PRIORITY) [NULL is equivalent to MAX(PRIORITY + 1)] ... in the case of ties in PRIORITY, break using lowest LINEITEM
FIELDS:
USER,
LINEITEM,
NUMBER,
PRIORITY
VALUES: ('X' signifies desired combination)
USER LINEITEM NUMBER PRIORITY
-------------------------------------
1 1 12345 NULL
1 2 23456 2
1 3 34567 1 X
2 1 9876 3
2 2 98765 1 X
2 3 12345 2
2 4 23456 1
3 1 23456 NULL X
3 2 12345 NULL
4 1 34567 NULL
4 2 45678 NULL
4 3 12345 1 X
4 4 12345 2
4 5 23456 1
Thanks in advance.
In response to PM 77-1,
My current method:
SELECT table1.user,table1.number
FROM table1
JOIN (
SELECT user,
CAST(MIN((COALESCE(priority,999) *
(10 ^ (5 - LEN(COALESCE(CAST(priority AS VARCHAR),'999'))))) +
lineitem) AS VARCHAR) AS selector
FROM table1 GROUP BY user
) AS table2
ON table1.user = table2.user
AND table1.lineitem = CAST(RIGHT(table2.selector, 1) AS int)
ORDER BY table1.user;
Use ROW_NUMBER:
SQL Fiddle
;WITH Cte AS(
SELECT *,
ROW_NUMBER() OVER(
PARTITION BY [User]
ORDER BY
CASE WHEN Priority IS NULL THEN 1 ELSE 0 END,
Priority,
LineItem
) AS rn
FROM tbl
)
SELECT
[User], LineItem, Number, Priority
FROM Cte
WHERE rn = 1