I have this long table:
col1
col2
col3
Personne1
nom
Aurélie
Personne1
prenom
Dupont
Personne1
age
25
Personne2
nom
Stéphane
Personne2
prenom
Blanc
Personne2
age
45
I want to transpose it to this shape:
col
nom
prenom
age
Personne1
Aurélie
Dupont
25
Personne2
Stéphane
Blanc
45
I tried this code in Oracle SQL developer, but it doesn't work:
select *
from table as SourceTable
pivot (max(col3) for col2 in ('nom', 'prenom', 'age'));
PS: the "age" column is string
Could you help please?
Thank you!
(Code you posted, as well as tags suggest that you use Oracle database. Code that follows uses Oracle.)
One option is to use conditional aggregation.
Sample data:
SQL> with test (col1, col2, col3) as
2 (select 'pers1', 'nom' , 'Aurelie' from dual union all
3 select 'pers1', 'prenom', 'Dupont' from dual union all
4 select 'pers1', 'age' , '25' from dual union all
5 --
6 select 'pers2', 'nom' , 'Stephane' from dual union all
7 select 'pers2', 'prenom', 'Blanc' from dual union all
8 select 'pers2', 'age' , '45' from dual
9 )
Query:
10 select col1,
11 max(case when col2 = 'nom' then col3 end) nom,
12 max(case when col2 = 'prenom' then col3 end) prenom,
13 max(case when col2 = 'age' then col3 end) age
14 from test
15 group by col1;
COL1 NOM PRENOM AGE
----- -------- -------- --------
pers1 Aurelie Dupont 25
pers2 Stephane Blanc 45
SQL>
Or, pivot - as you tried:
10 select *
11 from test
12 pivot (max(col3) for col2 in ('nom', 'prenom', 'age'));
COL1 'nom' 'prenom' 'age'
----- -------- -------- --------
pers1 Aurelie Dupont 25
pers2 Stephane Blanc 45
SQL>
You commented that you have problems with age being a string; it certainly is a string as COL3 contains names so it can't be a NUMBER datatype column. Though, it doesn't make any problems.
SQL> desc test
Name Null? Type
----------------------------------------- -------- ----------------------------
COL1 CHAR(5)
COL2 VARCHAR2(6)
COL3 VARCHAR2(8)
SQL> select * from test;
COL1 COL2 COL3
----- ------ --------
pers1 nom Aurelie
pers1 prenom Dupont
pers1 age 25
pers2 nom Stephane
pers2 prenom Blanc
pers2 age 45
6 rows selected.
SQL> select *
2 from test
3 pivot (max(col3) for col2 in ('nom', 'prenom', 'age'));
COL1 'nom' 'prenom' 'age'
----- -------- -------- --------
pers1 Aurelie Dupont 25
pers2 Stephane Blanc 45
SQL>
Related
I'm trying to concatenate two columns, with the values separated by '/' only if both columns are not null.
If either column is null then '/' should not be printed.
Example:
current output :
concat(concat(purpose,'/'),priority)
abc/xyz
/xyz
abc/
Expected Output :
abc/xyz
xyz
abc
Use CASE (see line #9):
SQL> with test (col1, col2) as
2 (select 'abc', 'xyz' from dual union all
3 select null , 'xyz' from dual union all
4 select 'abc', null from dual
5 )
6 select col1,
7 col2,
8 --
9 col1 || case when col1 is not null and col2 is not null then '/' end || col2 result
10 from test;
COL1 COL2 RESULT
----- ----- -------
abc xyz abc/xyz
xyz xyz
abc abc
SQL>
Or, use a trick - remove leading/trailing (read: both) slashes:
SQL> with test (col1, col2) as
2 (select 'abc', 'xyz' from dual union all
3 select null , 'xyz' from dual union all
4 select 'abc', null from dual
5 )
6 select col1,
7 col2,
8 trim(both '/' from col1 ||'/'|| col2) result
9 from test;
COL1 COL2 RESULT
----- ----- -------
abc xyz abc/xyz
xyz xyz
abc abc
SQL>
Here we are using CASE WHEN to look for the conditions explained in the question. The first condition is checking if both columns are not Null. If that is the case then we concat the two columns together with
/ in between.
If we have a case when one of the column is Null then we simply return the value of the column which is not Null. For that purpose we are using COALESCE. COALESCE always returns the firs non-null value.
Select
col_one,
col_two,
case when col_one is not null and col_two is not null
then concat(col_one, "/",col_two)
else COALESCE(col_one,col_two) end as concat_final
from table
I need to find the sum,avg,max and min of a column:
Table_ab
col1 | col2 | col3
ab |10 am | {10,20,30}
ab |10.15am | {20,30,40}
Expected result
col1 | col2 | col3 | sum_col3 | avg_col3 | max_col3 | min_col3
ab |10 am |{10,20,30} |60 |20 |30 | 10
Not the best data model, as you've already been told. Anyway: one (usual) option is to split values in col3 into rows to perform those calculations. Here's how (sample data in lines #1 - 4; query begins at line #6):
SQL> with table_ab (col1, col2, col3) as
2 (select 'ab', '10 am' , '10,20,30' from dual union all
3 select 'ab', '10.15am', '20,30,40' from dual
4 ),
5 -- split col3 into rows
6 temp as
7 (select col1,
8 col2,
9 col3,
10 to_number(regexp_substr(col3, '[^,]+', 1, column_value)) val
11 from table_ab cross join
12 table(cast(multiset(select level from dual
13 connect by level <= regexp_count(col3, ',') + 1
14 ) as sys.odcinumberlist))
15 )
16 -- aggregate!
17 select col1,
18 col2,
19 col3,
20 sum(val) sum_col3,
21 avg(val) avg_col3,
22 max(val) max_col3,
23 min(val) min_col3
24 from temp
25 group by col1, col2, col3;
CO COL2 COL3 SUM_COL3 AVG_COL3 MAX_COL3 MIN_COL3
-- ------- -------- ---------- ---------- ---------- ----------
ab 10.15am 20,30,40 90 30 40 20
ab 10 am 10,20,30 60 20 30 10
SQL>
I'm attempting to flatten the data I have as I'm getting multiple rows that largely contain the same data, it'll currently comes out looking like this:
col1 col2 col3 col4 col5 col6
---- ---- ---- ---- ---- ----
ABC DEF 123 456 1 24
ABC DEF 123 456 2 48
GHI JKL 789 010 1 6
GHI JKL 789 010 2 12
I want the output to be this:
col1 col2 col3 col4 col5 col6 col7 col8
---- ---- ---- ---- ---- ---- ---- ----
ABC DEF 123 456 24 48
GHI JKL 789 010 6 12
This will be done based off of the value of column 5, if it's "1", the value of column 6 moves to column 7, if it's "2", it moves to column 8. This should only happen when the first columns are all matches as well.
You can use conditional aggregation
select col1,col2,col3,col4,null as col5, null as col6,
max(case when col5=1 then col6 end) as col7,
max(case when col5=2 then col6 end) as col8
from tablename
group by col1,col2,col3,col4
You can try this solution using DECODE:
WITH tbl AS(
select 'ABC' as col1,'DEF' as col2,123 as col3,456 as col4,1 as col5,24 as col6 from dual union all
select 'ABC','DEF',123,456,2,48 from dual union all
select 'GHI','JKL',789,010,1,6 from dual union all
select 'GHI','JKL',789,010,2,12 from dual
)
select col1,
col2,
col3,
col4,
decode(min(col5), 1, null, min(col5)) as col5,
decode(max(col5), 2, null, max(col5)) as col6,
decode(min(col5), 1, min(col6), null) as col7,
decode(max(col5), 2, max(col6), null) as col8
from tbl
group by col1, col2, col3, col4
order by 1,2;
Output:
I would like to run below query:
SELECT
*
FROM
TABLE1
WHERE
COL1 = :DynamicValue1
AND COL2 = :DynamicValue2
USING
USERENTEREDVALUE1, USERENTEREDVALUE2;
I don't want to use EXECUTE IMMEDIATE.
How can I use using keyword in select query?
When I run this I get pop up to enter value but it gives error
Ora-00933
You may use substitution variables
DEFINE lname = 'Rogers'
DEFINE mgrid = 122
SELECT *
FROM employees
WHERE last_name = '&lname'
AND manager_id = '&mgrid';
When you run this in SQL developer or SQL* Plus, you get
old:SELECT *
FROM employees
WHERE last_name = '&lname'
AND manager_id = &mgrid
new:SELECT *
FROM employees
WHERE last_name = 'Rogers'
AND manager_id = 122
EMPLOYEE_ID FIRST_NAME LAST_NAME EMAIL PHONE_NUMBER HIRE_DAT JOB_ID SALARY COMMISSION_PCT MANAGER_ID DEPARTMENT_ID
----------- -------------------- ------------------------- ------------------------- -------------------- -------- ---------- ---------- -------------- ---------- -------------
134 Michael Rogers MROGERS 650.127.1834 26-08-06 ST_CLERK 2900 122 50
Or use Bind variables
VARIABLE lname VARCHAR2(40)
VARIABLE mgrid NUMBER
EXEC :lname := 'Rogers'
EXEC :mgrid := 122
VARIABLE x REFCURSOR
BEGIN
OPEN :x FOR SELECT *
FROM employees
WHERE last_name =:lname
AND manager_id =:mgrid;
END;
/
PRINT x
Result
PL/SQL procedure successfully completed.
PL/SQL procedure successfully completed.
PL/SQL procedure successfully completed.
EMPLOYEE_ID FIRST_NAME LAST_NAME EMAIL PHONE_NUMBER HIRE_DAT JOB_ID SALARY COMMISSION_PCT MANAGER_ID DEPARTMENT_ID
----------- -------------------- ------------------------- ------------------------- -------------------- -------- ---------- ---------- -------------- ---------- -------------
134 Michael Rogers MROGERS 650.127.1834 26-08-06 ST_CLERK 2900 122 50
I'm not sure if you're doing pl/sql, but if you do, you can simply add variables to you query:
declare
USERENTEREDVALUE1 VARCHAR2(100) := 'value1';
USERENTEREDVALUE2 VARCHAR2(100) := 'value2';
RESULTVALUE VARCHAR2(100);
begin
SELECT COL3
INTO RESULTVALUE
FROM (
SELECT 'value1' COL1, 'value2' COL2, 'Ok' COL3 FROM dual UNION ALL
SELECT 'value3' COL1, 'value4' COL2, 'NOK' COL3 FROM dual
) TABLE1
WHERE COL1 = USERENTEREDVALUE1
AND COL2 = USERENTEREDVALUE2;
dbms_output.put_line('RESULTVALUE: ' || RESULTVALUE);
end;
i want to convert rows into columns using PIVOT function.
Example is below
Table
EMP No EMP Name
------- --------
1 ABC
2 PQR
Output should be
Col1 Col2
---- ----
Emp No 1
Emp Name ABC
EMP No 2
Emp Name PQR
I am ok with loop and all however we should have used PIVOT, have serached google however has not got anything matching.
Please suggest and send some sample code.
Actually for you requirement, you need unpivot, not pivot. But for that, datatype of both columns should be same, character in this case
with tab(emp_no, emp_name) as (
select '1' ,'abc' from dual union all
select '2' ,'PQR' from dual)
----
--End of Data Perparation
----
select *
from tab
unpivot (col2 for col1 in ( emp_no as 'EMP No', emp_name as 'Emp Name'));
Output
| COL1 | COL2 |
|----------|------|
| EMP No | 1 |
| Emp Name | abc |
| EMP No | 2 |
| Emp Name | PQR |
I'm not sure if this can be done using PIVOT. You can select the columns separately and UNION them.
select 'Emp No' col1, emp_no col2 from tab
union all
select 'Emp Name', emp_name from tab;
Note that, both the columns should be of same datatype. Else you need to cast/convert one of them.
Also, the result may not be in the order you want. You need to sepecify the order by clause explicitly.
select col1, col2 from(
select 'Emp No' col1, emp_no col2, emp_no from tab
union all
select 'Emp Name', emp_name, emp_no from tab
)
order by emp_no, case col1 when 'Emp No' then 1 else 2 end;
sqlfidle.