I want to flip all rows to columns. So if have following 5 columns
with 3 data rows
ACCT_ID NAME PHONE MOBILE ALTERNATIVE_NAME
01 JOE BROWN 0456-9992-6666 07767828432 ZOE BROWN
02 GILL SHARP 0456-9992-6666 07763928432 BILL SHARP
03 ZAC LOWE 0236-9992-5644 07663925672 LUKE LOWE
I want the result set to look as follows. So have 3 columns and 5 rows.
COL headings (COL1 - COL3) are only added to make clearer, i don't need
columns headings
COL1 COL2 COL3
01 02 03
JOE BROWN GILL SHARP ZAC LOWE
0456-9992-6666 0456-9992-6666 0236-9992-5644
07767828432 07763928432 07663925672
ZOE BROWN BILL SHARP LUKE LOWE
I tried using PIVOT on one column (acct_id)
Select *
from
(
select ACCT_ID
from TABLE
)
pivot
(
max(ACCT_ID) as ACCT_ID
for ACCT_ID in ('01','02','03')
)
This returns following
'01'_ACCT_ID '02'_ACCT_ID '03'_ACCT_ID
01 02 03
Which is on the right track. Just need extending to include the other 4 columns (NAME,PHONE,MOBILE,ALTERNATIVE_CONTACT), listed under the associated acct_id.
So end up with 5 rows.
Can anyone help.
You could brute-force it with a series of case expressions:
select max(case when acct_id = '01' then acct_id end) as col1,
max(case when acct_id = '02' then acct_id end) as col2,
max(case when acct_id = '03' then acct_id end) as col3
from your_table
union all
select max(case when acct_id = '01' then name end),
max(case when acct_id = '02' then name end),
max(case when acct_id = '03' then name end)
from your_table
union all
select max(case when acct_id = '01' then phone end),
max(case when acct_id = '02' then phone end),
max(case when acct_id = '03' then phone end)
from your_table
... repeat for other columns
COL1 COL2 COL3
-------------- -------------- --------------
01 02 03
JOE BROWN GILL SHARP ZAC LOWE
0456-9992-6666 0456-9992-6666 0236-9992-5644
...
Or you could unpivot and re-pivot, which is messy and probably doing more work than is really necessary:
select col1, col2, col3
from (
select t.*, t.acct_id as col_id
from your_table t
)
unpivot
(
value for heading in (acct_id, name, phone, mobile, alternative_name)
)
pivot
(
max(value) for col_id in ('01' as col1, '02' as col2, '03' as col3)
)
order by case heading when 'ACCT_ID' then 1 when 'NAME' then 2 when 'PHOEN' then 3
when 'MOBILE' then 4 when 'ALTERNATIVE_NAME' then 5 end
COL1 COL2 COL3
-------------- -------------- --------------
01 02 03
JOE BROWN GILL SHARP ZAC LOWE
07767828432 07763928432 07663925672
ZOE BROWN BILL SHARP LUKE LOWE
0456-9992-6666 0456-9992-6666 0236-9992-5644
The subquery to add the dummy col_id expression is only there so you can picot on the acct_id and also include it in the result.
If you want to include the original column names as a heading column in the final result, add that to the first select list:
select heading, col1, col2, col3
from (
...
This only works if you know there will be (at most) three rows (and is based on fixed account IDs, though that is fixable); if you don't know how many columns your final result will need to have then you need to look at dynamic SQL.
Related
I am new to PL/SQL
I have a code like this
SELECT f.code,f.date,f.amt, row_number() OVER (PARTITION BY f.code ORDER BY f.date DESC) ranki
FROM advance.alloc f
and shows
CODE DATE AMT ranki
122 12/31/2016 3 1
122 12/31/2015 7 2
122 12/31/2014 3 3
123 6/30/2015 3 1
125 6/30/2015 2 1
125 12/31/2014 8 2
Logic is this
if DATE = 12/__/__ AND ranki = 1 THEN ranki 1, so 122 picks 12/31/2016 3
if DATE = 6/30/__ AND ranki = 1 AND if ranki = 2 exists THEN then pick the second one,so 125 picks 12/31/2014 8
if 6/30__ and ranki is ONLY 1 shows Blank on date LIKE 123
so I would like to show
122 12/31/2016 3
123 __________ 3
125 12/31/2014 8
How can I code like this PL/SQL?
WHEN to_char(af.date,'MM') = 12 AND af.ranki = 1 THEN af.date END
I could code first logic, but I can not figure out how to code the rest of the logic
Thanks
Why in PL/SQL? Or do you mean "in Oracle SQL"? (The solution below uses standard analytic functions, so it is not specific to Oracle.)
Add more information through analytic functions, in addition to ranki. Extract the month from the row with ranki = 1, and also the total count for each code. Then the WHERE clause can follow your logic step by step.
with
f ( code, dt, amount ) as (
select 122, to_date('12/31/2016', 'mm/dd/yyyy'), 3 from dual union all
select 122, to_date('12/31/2015', 'mm/dd/yyyy'), 7 from dual union all
select 122, to_date('12/31/2014', 'mm/dd/yyyy'), 3 from dual union all
select 123, to_date( '6/30/2015', 'mm/dd/yyyy'), 3 from dual union all
select 125, to_date( '6/30/2015', 'mm/dd/yyyy'), 2 from dual union all
select 125, to_date('12/31/2014', 'mm/dd/yyyy'), 8 from dual
)
-- End of simulated data (for testing purposes only, not part of the solution).
-- SQL query begins BELOW THIS LINE.
select code, case when mth = 12 or ranki = 2 then dt end as dt, amount
from ( select code, dt, amount,
first_value(extract (month from dt))
over (partition by code order by dt desc) as mth,
row_number() over (partition by code order by dt desc) as ranki,
count(*) over (partition by code) as cnt
from f
)
where mth = 12 and ranki = 1
or cnt = 1
or mth = 6 and ranki = 2
;
CODE DT AMOUNT
---- ---------- ------
122 12/31/2016 3
123 3
125 12/31/2014 8
This is how I have a sample table in SQLITE
ID NAME AGE ADDRESS SALARY
1 Paul 32 California 20000.0
2 Allen 25 Texas 15000.0
3 Teddy 23 Norway 20000.0
4 Mark 25 Rich-Mond 65000.0
5 David 27 Texas 85000.0
6 Kim 22 South-Hall 45000.0
7 Paul 32 California 20000.0
8 Allen 25 Texas 15000.0
9 Teddy 23 Norway 20000.0
What I want to achieve is a join on my SQLITE table on these two queries
select AGE, count(*) as SALARYLESSTHAN45 from company where salary < 45000 group by salary
select AGE, count(*) as SALARYMORETHAN45 from company where salary > 45000 group by salary
I tried the following
select AGE, count(*) as SALARYLESSTHAN45 from company where salary < 45000 group by salary ) T1
INNER JOIN
select AGE, count(*) as SALARYMORETHAN45 from company where salary > 45000 group by salary ) T2
ON T1.AGE = T2.AGE
but cannot get this to work...
Can someone share an example of how to achieve this in SQLITE ?
A join on two different tables would look like this:
SELECT ... FROM Tab1 JOIN Tab2 ON ...
To do the join on the result of a query, you have to replace the table name with a subquery:
select AGE,
SALARYLESSTHAN45,
SALARYMORETHAN45
from (select AGE,
count(*) as SALARYLESSTHAN45
from company
where salary < 45000
group by salary)
join (select AGE,
count(*) as SALARYMORETHAN45
from company
where salary > 45000
group by salary)
using (AGE);
Here is the code (simulating full outer join for sqlite3):
SELECT EMP_ID, ID, NAME, DEPT FROM COMPANY LEFT OUTER JOIN DEPARTMENT ON COMPANY.ID = DEPARTMENT.EMP_ID
union
SELECT EMP_ID, ID, NAME, DEPT FROM department LEFT OUTER JOIN company ON COMPANY.ID = DEPARTMENT.EMP_ID
The company table has the columns: id, name, age, address, salary.
The department table has the columns: id, dept, emp_id.
The problem is that both tables have the id column, but I only want to select the id column from company. How can I do this?
Solved by using an alias:
SELECT EMP_ID, c.id, NAME, DEPT FROM COMPANY as c LEFT OUTER JOIN DEPARTMENT as d ON c.ID = d.EMP_ID
union
SELECT EMP_ID, c.id, NAME, DEPT FROM department as d LEFT OUTER JOIN company as c ON c.ID = d.EMP_ID;
This nicely illustrate the result of a full outer join:
3 Teddy
4 Mark
5 David
6 Kim
7 James
8 Kitos
9 Paul
10 James
11 James
12 James
13 James
14 James
15 James
16 James
17 James
1 1 Paul IT Billing
2 2 Allen Engineering
77 Finance
Blank cells are null.
first off: thanks for looking; your time is appreciated!
to the point:
SCHEMA: for myTable
nonUniqueID YEAR MONTH DAY HOUR numericValue
1 2012 01 01 01 99.9
1 2012 01 01 02 65.2
1 2012 01 01 03 -88
7 2012 02 08 21 9.08
1 2012 01 01 09 99.913
1 2013 01 01 01 99.999999
Basically, it's two values nonUniqueID and numericValue with a granular date.
Now, i need to get the single greatest date in this entire database. With the data above, the expected result would be:
nonUniqueID YEAR MONTH DAY HOUR numericValue
1 2013 01 01 01 99.999999
Because this is SQLite, i know that i will end up having to use MAX() several times. The order will have to be MAX(YEAR) then MAX(MONTH) then MAX(DAY) then MAX(HOUR).
Basically, the query would work like this (i just don't know enough about SQL syntax to create the query):
Find all records with highest YEAR
From this set, find all records with highest MONTH
From this set, find all records with highest DAY
From this set, find all records with highest HOUR
return this record
Here is a SQL that i adapted from another StackExchange question that does not work
Select * From (
Select max(YEAR) as Y FROM myTable
union
Select max(MONTH) as M FROM myTable
union
Select max(DAY) as D FROM myTable
union
Select max(HOUR) as H FROM myTable
) myTable;
which returns
Y
-----
21
08
02
2013
Compare this to expected out:
nonUniqueID YEAR MONTH DAY HOUR numericValue
1 2013 01 01 01 99.999999
it returned 4 records instead of the one record with the 4 values.
Can somebody please help me with my query? THANK YOU!
Try this
SELECT nonUniqueID , YEAR , MONTH , DAY , HOUR , numericValue FROM myTable as a
INNER JOIN (Select max(MONTH) FROM myTable) as b
ON a.YEAR = B.YEAR
INNER JOIN (Select max(DAY) FROM myTable) as c
ON b.YEAR = c.YEAR
INNER JOIN (Select max(HOUR) FROM myTable) as d
ON c.YEAR = d.YEAR
WHERE a.YEAR = (Select max(YEAR) FROM myTable)
It returns 4 values because you use UNION
it means that the result are join in one column
EDIT
Ive just updated my answer see if that works Im not quite sure to the performance of this query
I need some help to build SQL Query. I have table having data like:
ID Date Value1 Value2 Code
1 12/01/2009 4 3.5 abc
2 12/02/2009 3 4.0 abc
3 11/03/2009 6 8.5 xyz
4 11/01/2009 2 5.5 abc
5 11/02/2009 4 6.0 xyz
6 12/03/2009 5 7.0 xyz
I need to show result something like...
---------
Code | Data | November(Sum of Values in month) December Jan Feb
abc | Value1 | 2 7 0 0
| Value2 | 5 7 0 0
xyz | Value1 | 10 5 0 0
| Value2 | 14 7 0 0
----------
I need sum of value in each month as in above data in columns group by code.
Have a look at this solution, and let me know what you think.
You have to use both PIVOT and UNPIVOT in this instance to get the result you are looking for. Hope this helps.
DECLARE #Table TABLE(
ID INT,
Date DATETIME,
Value1 INT,
Value2 FLOAT,
Code VARCHAR(10)
)
INSERT INTO #Table (ID,Date,Value1,Value2,Code) SELECT 1,'12/01/2009',4,3,'abc'
INSERT INTO #Table (ID,Date,Value1,Value2,Code) SELECT 2,'12/02/2009',3,4,'abc'
INSERT INTO #Table (ID,Date,Value1,Value2,Code) SELECT 3,'11/03/2009',6,8,'xyz'
INSERT INTO #Table (ID,Date,Value1,Value2,Code) SELECT 4,'11/01/2009',2,5,'abc'
INSERT INTO #Table (ID,Date,Value1,Value2,Code) SELECT 5,'11/02/2009',4,6,'xyz'
INSERT INTO #Table (ID,Date,Value1,Value2,Code) SELECT 6,'12/03/2009',5,7,'xyz'
;WITH UnPvt AS (
SELECT *
FROM (
SELECT Code,
DATENAME(MM, Date) MonthNameVal,
SUM(Value1) Value1,
SUM(Value2) Value2
FROM (
SELECT Code,
Date,
CAST(Value1 AS FLOAT) Value1,
Value2
FROM #Table
) v
GROUP BY Code,
DATENAME(MM, Date)
) Sub
UNPIVOT
(
Vals FOR RowValues IN (Value1, Value2)
) AS UnPvt
)
SELECT *
FROM UnPvt
PIVOT (
SUM(Vals)
FOR MonthNameVal IN ([January],[February],[March],[April],[May],[June],[July],[August],[September],[October],[November], [December])
) AS pvt
ORDER BY Code, RowValues
Have a look at
SQL SERVER – PIVOT and UNPIVOT Table
Examples
Give the New PIVOT and UNPIVOT
Commands in SQL Server 2005 a
Whirl
Using PIVOT and UNPIVOT
This isn't quite what you asked for because the number of columns is fixed, but I think it's a better way to what you want in SQL:
SELECT Code, 'Value1' As Data, MONTH(Date) AS Month, YEAR(Date) AS Year, SUM(Value1) AS Sum
FROM Table1
GROUP BY Code, MONTH(Date), YEAR(Date)
UNION ALL
SELECT Code, 'Value2' As Data, MONTH(Date) AS Month, YEAR(Date) AS Year, SUM(Value2) AS Sum
FROM Table1
GROUP BY Code, MONTH(Date), YEAR(Date)
ORDER BY Code, Data, Month, Year
Example output:
Code Data Month Year Sum
abc Value1 11 2009 2
abc Value1 12 2009 7
abc Value2 11 2009 5
abc Value2 12 2009 7
xyz Value1 11 2009 10
xyz Value1 12 2009 5
xyz Value2 11 2009 14
xyz Value2 12 2009 7
I'd recommend that you use a bit of non-SQL code to reformat the result into exactly what you asked for before displaying it to the user rather than trying to return a variable number of columns in SQL.