Rearrange data to make pivot chart - excel-2007

I am very new to Excel and have so far done a few basic pivot tables/charts.
I am trying to rearrange my source data to make a column chart where credits are shown in green and debits in red.
Here's my original data I get from a database. Please note there's 3 sets of values A, B, C.
Set1 A, B, C refers to Credits
Set2 A, B, C refers to debits
Set3 A, B, C is the difference between Set1 A - Set2 A and so on..
I need to make a chart like the one below, Set1 of A,B,Cs are the green columns, Set2 of A, B, Cs are the red columns. Set3 A, B, Cs is hte difference displayed on top.
How do I do this?
This is what I have done so far:
I hand edited and rearranged my original dataset to look like this: It was quite a bit of work to do this since I have a large amount of data.
Then I could make a chart out of this. But what I would like to know is if there's a better way to achieve this. Thanks much!
Update: Here's the data sample
+------+--------+--------+--------+--------+--------+--------+--------+--------+--------+
| Year | Set1 A | Set1 B | Set1 C | Set2 A | Set2 B | Set2 C | Set3 A | Set3 B | Set3 C |
+------+--------+--------+--------+--------+--------+--------+--------+--------+--------+
| 2010 | 58 | 33 | 111 | 0 | 0 | 300 | 58 | 33 | -189 |
| 2011 | 56 | 33 | 112 | 0 | 0 | 300 | 56 | 33 | -188 |
| 2012 | 56 | 33 | 112 | 0 | 0 | 300 | 56 | 33 | -188 |
| 2013 | 56 | 33 | 112 | 0 | 0 | 300 | 56 | 33 | -188 |
| 2014 | 56 | 30 | 102 | 0 | 0 | 300 | 56 | 30 | -198 |
| 2015 | 134 | 0 | 0 | 190 | 0 | 60 | -56 | 0 | -60 |
+------+--------+--------+--------+--------+--------+--------+--------+--------+--------+

If anyone is interested, I was able to rearrange data using the Excel add-in 'PowerQuery'. Powerquery is available for Excel 2010 Professional and beyond. It let me unpivot my table data and with a few clicks I got it to work. Thanks.

Related

Unpivot or transform data using MS Access Query

Good afternoon guru's!
I'm hoping someone with Access & SQL experience (and time) would be able to write some SQL code that I could use in MS Access to transform/unpivot some data. I guess it's a bit like a an unpivot.
Current table "tbl_Weekly_Forecast" is structured like this;
Item | A | B | C | D |
-------------------------------
61000224 | 1 | 2 | 3 | 4 |
64000123 | 25 | 25 | 25 | 25 |
66400005 | 38 | 38 | 37 | 37 |
Desired query output is like this;
Item | Period | Forecast |
-------------------------------
61000224 | A | 1 |
61000224 | B | 2 |
61000224 | C | 3 |
61000224 | D | 4 |
64000123 | A | 25 |
64000123 | B | 25 |
64000123 | C | 25 |
64000123 | D | 25 |
66400005 | A | 38 |
66400005 | B | 38 |
66400005 | C | 37 |
66400005 | D | 37 |
There are actually 24 columns to be unpivoted in table "tbl_Weekly_Forecast", so I'm hoping I'll be able to expand or add in the column names in to the SQL code and expand it myself.
I have spent about a day trying advice from others who have asked similar questions here, but unfortunately have very little SQL experience and have failed miserably so far. Any help would be most appreciated!
Thank you!
You can simply use UNION ALL as follows:
SELECT ITEM, 'A' PERIOD, A AS FORECAST FROM YOUR_TABLE
UNION ALL
SELECT ITEM, 'B' PERIOD, B AS FORECAST FROM YOUR_TABLE
UNION ALL
SELECT ITEM, 'C' PERIOD, C AS FORECAST FROM YOUR_TABLE
UNION ALL
SELECT ITEM, 'D' PERIOD, D AS FORECAST FROM YOUR_TABLE

Using a Group BY or PARTITION on multiple columns where records are grouped together if ANY of the columns return a match

Let's say I have the following table:
Record_ID | Match_criteria_1 | Match_criteria_2 | Match_criteria_3 | Dollars
1 | A | V | F | 10
2 | A | W | G | 20
3 | B | W | H | 30
4 | B | X | I | 40
5 | C | Y | F | 50
6 | C | Z | J | 60
If I try to use a 'GROUP BY' or 'Over (PARTITION BY)' on Match_criteria_1, Match_criteria_2, and Match_criteria_3, I would end up with separate 6 groups/partitions.
SELECT *, sum(Dollars) OVER (PARTITION BY Match_criteria_1, Match_criteria_2, Match_Criteria_3) AS Total_Dollars
FROM My_table
Record_ID | Match_criteria_1 | Match_criteria_2 | Match_criteria_3 | Dollars | Total_Dollars
1 | A | V | F | 10 | 10
2 | A | W | G | 20 | 20
3 | B | W | H | 30 | 30
4 | B | X | I | 40 | 40
5 | C | Y | F | 50 | 50
6 | C | Z | J | 60 | 60
As you can see, none of the records have the same Match_criteria_1, Match_criteria_2, and Match_criteria_3.
But what if I wanted to group records that have the same Match_criteria_1, Match_criteria_2 OR Match_criteria_3?
So using my example, Record 1 matches with Record 2 due to Match_criteria_1, Record 2 matches with Record 3 due to Match_criteria_2, Record 3 matches with Record 4 due to Match_criteria_1, Record 5 matches with Record 1 due to Match_Criteria_3, and Record 6 matches with Record 5 due to Match_criteria 1 (so sort of a transitive property thing going on). The desired result then is :
Record_ID | Match_criteria_1 | Match_criteria_2 | Match_criteria_3 | Dollars | Total_Dollars
1 | A | V | F | 10 | 210
2 | A | W | G | 20 | 210
3 | B | W | H | 30 | 210
4 | B | X | I | 40 | 210
5 | C | Y | F | 50 | 210
6 | C | Z | J | 60 | 210
where Total_dollars is the sum of every record due to the fact that all six policies match with each other due to transitivity. So Records 1 and 6 may have no match criteria in common but they are still grouped together because they both match with Record 5.
Perhaps I am understanding this incorrectly, but I think you could just get the total dollars for all rows that match other rows and join to that? I'm not sure exactly what your expected output should be if a row doesn't match. This answer will still include that row, but the total dollars would not include the amount in that row.
SELECT test.*, total_dollars
FROM test,
(SELECT sum(dollars) as total_dollars
FROM (select distinct test.* FROM test
JOIN test test2 ON (ARRAY[test.match_criteria_1, test.match_criteria_2, test.match_criteria_3] && ARRAY[test2.match_criteria_1, test2.match_criteria_2, test2.match_criteria_3])
AND test.record_id != test2.record_id order by 1
) sub)
sub2;
I added another row that shouldn't match any of the others:
insert into test VALUES (7, 'M', 'N', 'O', 100);
and here are the results:
record_id | match_criteria_1 | match_criteria_2 | match_criteria_3 | dollars | total_dollars
-----------+------------------+------------------+------------------+---------+---------------
1 | A | V | F | 10 | 210
2 | A | W | G | 20 | 210
3 | B | W | H | 30 | 210
4 | B | X | I | 40 | 210
5 | C | Y | F | 50 | 210
6 | C | Z | J | 60 | 210
7 | M | N | O | 100 | 210
(7 rows)

group by case condition followed by union of two columns

I have the following columns in table Sales :
Category1,priceA,priceB,Category2,costA,costB,type.(some items in category1 are same as category2)
sum(priceA), sum(priceB)
are to be grouped by category1,type.
sum(costA), sum(costB)
are to be grouped by category2,type.
I need the final output as
Union(category1,category2) as category3 ,sum(priceA)+sum(costA),sum(priceB)+sum(costB),type
to be grouped by UNION(category1+category2),type.
(sum(priceA)+sum(costA) would happen whenever items in category1 matches with category2 and same would be for sum(priceB)+sum(costB))
I tried to do it by
select category1,sum(priceA),sum(priceB),type group by category1,type
UNION ALL
select category2,sum(costA),sum(costB),type group by category2,type
Then following it up with another sum and group by. But I want to know how to do it without separately selecting and avoiding the union of basically 2 tables. Can I use group by followed by case statement here? Actually the table I referred as sales is an inner join of multiple tables , hence the motivation to not use select on it separately on two occasaions( in my actual case it would be union of 4 select queries on the table which makes the query look really big too). Plus I dont have permission to create procedure so no PL/SQL. Any fancy way for the above situation which will shorten the query and improve the performance ?
EDIT- SAMPLE DATA (Category1,PriceA,PriceB,Category2,CostA,CostB,Type)
+-----+----+----+-----+----+----+---+
| AUS | 20 | 25 | UK | 35 | 40 | X |
| UK | 30 | 26 | SA | 32 | 40 | Y |
| USA | 22 | 24 | NZ | 38 | 36 | Z |
| BRA | 16 | 10 | USA | 25 | 25 | Z |
| RUS | 20 | 15 | UK | 20 | 30 | X |
+-----+----+----+-----+----+----+---+
Which I divided into union of two tables as these:
+-----+----+----+---+
| AUS | 20 | 25 | X |
| UK | 30 | 26 | Y |
| USA | 22 | 24 | Z |
| BRA | 16 | 10 | Z |
| RUS | 20 | 15 | X |
+-----+----+----+---+
And
+-----+----+----+---+
| UK | 55 | 70 | X |
| SA | 33 | 40 | Y |
| NZ | 38 | 36 | Z |
| USA | 25 | 25 | Z |
+-----+----+----+---+
Final output would be like :
+-----+----+----+---+
| UK | 55 | 70 | X |
| UK | 30 | 26 | Y |
| NZ | 38 | 36 | Z |
| USA | 47 | 49 | Z |
| AUS | 20 | 25 | X |
| SA | 32 | 40 | Y |
| BRA | 16 | 10 | Z |
| RUS | 20 | 15 | X |
+-----+----+----+---+
This will give you what you want. SQLFiddle.
with sample_data1 as (
select "Category1", "PriceA", "PriceB", "Type"
from sample_data
union all
select "Category2", "CostA", "CostB", "Type"
from sample_data
)
select "Category1", sum("PriceA"), sum("PriceB")
from sample_data1 sd1
group by "Category1", "Type"
You will have to have a union at some point, because you need to increase the number of rows from your original source table. You can't do it with just a CASE.

How to make rows shuffle?

There is a table with over 10+ rows, and now needed to shuffle all rows randomly and create a new table on it. any ideas ?
Using select * from table order by random() seems slow.
raw table is like,and the target column is separated into two parts:
+--------+------+--------+------+-----+--------+
| cst_id | name | salary | fund | age | target |
+--------+------+--------+------+-----+--------+
| 1 | a | 100 | Y | 33 | 0 |
| 2 | b | 200 | Y | 21 | 0 |
| 3 | c | 300 | Y | 45 | 0 |
| 4 | d | 400 | N | 26 | 0 |
| 5 | e | 500 | N | 37 | 0 |
| 6 | f | 600 | Y | 56 | 0 |
| 7 | g | 700 | Y | 44 | 0 |
| 8 | h | 800 | N | 22 | 1 |
| 9 | i | 900 | N | 38 | 1 |
| 10 | j | 1000 | Y | 61 | 1 |
| 11 | k | 1100 | N | 51 | 1 |
| 12 | l | 1200 | N | 21 | 1 |
| 13 | m | 1300 | Y | 32 | 1 |
| 14 | n | 1400 | N | 17 | 1 |
+--------+------+--------+------+-----+--------+
after:
+--------+------+--------+------+-----+--------+
| cst_id | name | salary | fund | age | target |
+--------+------+--------+------+-----+--------+
| 1 | a | 100 | Y | 33 | 0 |
| 2 | b | 200 | Y | 21 | 0 |
| 8 | h | 800 | N | 22 | 1 |
| 9 | i | 900 | N | 38 | 1 |
| 3 | c | 300 | Y | 45 | 0 |
| 13 | m | 1300 | Y | 32 | 1 |
| 14 | n | 1400 | N | 17 | 1 |
| 5 | e | 500 | N | 37 | 0 |
| 6 | f | 600 | Y | 56 | 0 |
| 7 | g | 700 | Y | 44 | 0 |
| 10 | j | 1000 | Y | 61 | 1 |
| 11 | k | 1100 | N | 51 | 1 |
| 4 | d | 400 | N | 26 | 0 |
+--------+------+--------+------+-----+--------+
Following explanation is to create NEW table from existing one with same data as in old one(same schema) with shuffled rows.
Create a new table and import all those rows and records from first table, randomly selected and ordered by the RAND() SQL function:
CREATE TABLE new_table SELECT * FROM old_table ORDER BY RAND()
Or if you have created a table identical to the structure of the old one, use INSERT INTO instead:
INSERT INTO new_table SELECT * FROM old_table ORDER BY RAND()
That is of course if you want to preserve the primary key identification of each row, which is most likely what you want to do with old tables because of the legacy code and data entity relationships. However, if you want a grand new table with all the shuffled records completely rearranged in order as if it’s for a different application, you can ignore the primary key or ID by not importing the ID field of the old table.
For instance, you got ID, col1 and col2 in the old table as data fields. To create a grand new reordered or shuffled rows version of old table:
CREATE TABLE new_table SELECT col1, col2 FROM old_table ORDER BY RAND()
And a new primary key ID will be automatically assigned to each of the rows in the new table.
But in SQL, Relations have no order. Rows in a relational database are not sorted. You may get different order while retrieving.

SQL Joining 2 Tables

I would like to merge two tables into one and also add a counter next to that. What i have now is
SELECT [CUCY_DATA].*, [DIM].[Col1], [DIM].[Col2],
(SELECT COUNT([Cut Counter]) FROM [MSD]
WHERE [CUCY_DATA].[Cut Counter] = [MSD].[Cut Counter]
) AS [Nr Of Errors]
FROM [CUCY_DATA] FULL JOIN [DIM]
ON [CUCY_DATA].[Cut Counter] = [DIM].[Cut Counter]
This way the data is inserted but where the values don't match nulls are inserted. I want for instance this
Table CUCY_DATA
|_Cut Counter_|_Data1_|_Data2_|
| 1 | 12 | 24 |
| 2 | 13 | 26 |
| 3 | 10 | 20 |
| 4 | 11 | 22 |
Table DIM
|_Cut Counter_|_Col1_|_Col2_|
| 1 | 25 | 40 |
| 3 | 50 | 45 |
And they need to be merged into:
|_Cut Counter_|_Data1_|_Data2_|_Col1_|_Col2_|
| 1 | 12 | 24 | 25 | 40 |
| 2 | 13 | 26 | 25 | 40 |
| 3 | 10 | 20 | 50 | 45 |
| 4 | 11 | 22 | 50 | 45 |
SO THIS IS WRONG:
|_Cut Counter_|_Data1_|_Data2_|_Col1__|_Col2__|
| 1 | 12 | 24 | 25 | 40 |
| 2 | 13 | 26 | NULL | NULL |
| 3 | 10 | 20 | 50 | 45 |
| 4 | 11 | 22 | NULL | NULL |
Kind regards, Bob
How are you getting the col1 and col2 values where there is no corresponding row in your DIM table? (Rows 2 and 4). Your "wrong" result is exactly correct, that's what the outer join does.