SQL query to Transpose columns into rows - tsql

can somebody help with a query for below problem
Return Table
Id Factor monthlyReturns price date
A1 0.2 0.001 2010-01-29
A1 0.2 0.003 2010-02-26
A1 0.2 0.004 2010-03-31
A1 0.2 0.004 2010-04-30
A2 0.1 0.001 2010-01-29
A2 0.1 0.001 2010-02-26
A2 0.1 0.001 2010-03-31
A2 0.1 0.001 2010-04-30
A3 0.3 0.03 2010-01-29
A3 0.3 0.04 2010-02-26
A3 0.3 0.05 2010-03-31
A3 0.3 0.05 2010-04-30
A4 0.4 0.12 2010-01-29
A4 0.4 0.12 2010-02-26
A4 0.4 0.14 2010-03-31
A4 0.4 0.15 2010-04-30
I want to convert this data into following format .Can somebody please suggest a query
A1 A2 A3 A4 Total
31-Jan-10 0.001 0.001 0.03 0.12 0.001*0.2(Factor for A1)+0.001*0.1(Factor forA2)+
0.03*0.3(Factor forA3)+ 0.12*0.4(Factor forA4)
28-Feb-10 0.003 0.001 0.04 0.12 Same as above
31-Mar-10 0.004 0.001 0.05 0.14 Same as above
30-Apr-10 0.004 0.001 0.05 0.15 Same as above
Thanks

below is the query you asked for, notice that you need to change the table name to yours.
a little explanation:
I assumed the Ids are limited to A1,A2,A3,A4. otherwise this will not work and you will need a more complexed solution.
first i created a common table expression of a pivoted table with all the factors grouped by date (assuming that there can not be two factors to the same id on the same date)
then, i join that with a pivoted table that holds all the monthly returns.
note: i used the sum function on the fields A1,A2,.. since i needed to group it by date and the select can only use aggregate function if the column is not in the group by clause.
this does not effect the values since you only have one row for each id on a particular date, but correct me if i'm wrong.
with FactorsByDate(PriceDate,FactorA1,FactorA2,FactorA3,FactorA4)
AS
(
SELECT [price date] AS Date,
SUM([A1]) AS A1, SUM([A2]) AS A2, SUM([A3]) AS A3, SUM([A4]) AS A4
FROM
(SELECT Id, Factor , [price date]
FROM TempTbl) AS SourceTable
PIVOT
(
SUM(Factor)
FOR Id IN ([A1], [A2], [A3], [A4])
) AS PivotTable
group by [price date]
)
SELECT Date,A1,A2,A3,A4, A1*FactorA1 + A2*FactorA2 + A3*FactorA3 + A4*FactorA4 AS Total
FROM
(
SELECT [price date] AS Date,
SUM([A1]) AS A1, SUM([A2]) AS A2, SUM([A3]) AS A3, SUM([A4]) AS A4
FROM
(SELECT Id, monthlyReturns , [price date]
FROM TempTbl) AS SourceTable
PIVOT
(
SUM(monthlyReturns)
FOR Id IN ([A1], [A2], [A3], [A4])
) AS PivotTable
group by [price date]
) AS monthlyReturns
INNER JOIN FactorsByDate ON FactorsByDate.PriceDate = monthlyReturns.Date

Related

getting sum of item quantities grouped by item groups

I have the following data:
LOC
ITEM
GROUP
MONTH
PCS
X
A1
A
01/01/2022
8
Y
A1
A
01/01/2022
76
Z
A1
A
01/01/2022
11
X
A2
A
01/01/2022
9
Y
A2
A
01/01/2022
19
Z
A2
A
01/01/2022
13
I need to get the sum of PCS for each LOC/ MONTH summed by GROUP
My tentative query so far is:
QUERY(DATA;"SELECT LOC,ITEM,GROUP,SUM(PCS) WHERE LOC='X' AND GROUP='A' AND MONTH='01/01/2022' GROUP BY LOC,GROUP,MONTH,PCS";1)
My expected results is:
LOC
GROUP
MONTH
PCS
X
A
01/01/2022
17
the test spreadsheet with data, formula results is here
Thank you in advance
use:
=QUERY(DATA;
"SELECT A,C,D,SUM(E)
WHERE A='"&SEL_L&"'
AND C='"&SEL_G&"'
AND D = date '"&TEXT(SEL_M; "e-m-d")&"' GROUP BY A,C,D"; 1)

Calculating a simple rate for "windows" within data

Battery % time charging
90 t1 yes
91 t2 yes
95 t3 no
89 t4 no
87 t5 no
80 t6 no
78 t7 yes
85 t8 yes
50 t9 no
40 t10 no
38 t11 no
20 t12 yes
I want to calculate battery depletion rate as :
change in battery / time taken
This should be calculated for ALL the windows when charging is 'no' (sandwiched in between 2 "yes"), and then the average of those rates should be taken.
So, for this dataset it should be:
95 - 80 / t6 - t3 = rate 1
50 - 38 / t11 - t9 = rate 2
average rate = ( rate 1 + rate 2 ) / 2
Please note there can be more than 2 windows of no's in the data
Here is my current code -
select ((max(battery_Percentage) - min (battery_Percentage)) / NULLIF(Extract(epoch FROM (max(time) - min(time))/3600),0)) as rate_of_battery_decline
from table
where
table.charging = 'no'
but this is not taking into account windows of no's in between the yes's as I want. Please help.
You have to separate the runs between the charging = 'yes' blocks:
with discharge_intervals as (
select battery_pct, tstamp,
sum((charging = 'yes')::int) over (order by tstamp) as ival_number,
charging = 'no' as keep
from cstats
), interval_rates as (
select ival_number,
(max(battery_pct) - min(battery_pct))
/ extract(epoch from max(tstamp) - min(tstamp)) as ival_rate
from discharge_intervals
where keep
group by ival_number
)
select avg(ival_rate)
from interval_rates;
Fiddle Here

Calculate Split Balances based on range in SQL

Need some help on splitting the daily balance based on the Min and Max range.
I have a table with an account with a balance 19447.83 in a balance table on one particular day.
I have a range table where for every product where the balance is split as follows
Range Table
Product_Code Product_Description Min_Range Max_Range Interest_Rate
2000-0100 Saving 0 4999.99 0.01
2000-0100 Saving 5000 9999.99 0.02
2000-0100 Saving 10000 49999.99 0.03
2000-1111 Senior Savings 0 4999.99 0.03
2000-1111 Senior Savings 5000 9999.99 0.04
2000-1111 Senior Savings 10000 49999.99 0.05
Balance Table
Date Balance Product_Code Product_Description AccountNo
28/02/2019 19447.83 2000-0100 Saving 3059123
27/02/2019 19557.61 2000-0100 Saving 3059123
26/02/2019 19976.01 2000-0100 Saving 3059123
25/02/2019 20530.91 2000-0100 Saving 3059123
28/02/2019 12345 2000-1111 Senior Savings 4059123
27/02/2019 5456 2000-1111 Senior Savings 4059123
26/02/2019 9999 2000-1111 Senior Savings 4059123
25/02/2019 7893 2000-1111 Senior Savings 4059123
The balance on 28/02/2019 19447.83 Should be split into
0 to 4999.99 0.01
5000 to 9999.99 0.02
10000 to 19447.83 0.03
This is fairly basic joining and arithmetic:
declare #r table(Product_Code varchar(20),Product_Description varchar(20),Min_Range decimal(10,2),Max_Range decimal(10,2),Interest_Rate decimal(10,2));
insert into #r values('2000-0100','Saving',0,4999.99,0.01),('2000-0100','Saving',5000,9999.99,0.02),('2000-0100','Saving',10000,49999.99,0.03),('2000-1111','Senior Savings',0,4999.99,0.03),('2000-1111','Senior Savings',5000,9999.99,0.04),('2000-1111','Senior Savings',10000,49999.99,0.05);
declare #b table(BalanceDate date,Balance decimal(10,2),Product_Code varchar(20),Product_Description varchar(20),AccountNo int);
insert into #b values('20190228',19447.83,'2000-0100','Saving',3059123),('20190227',19557.61,'2000-0100','Saving',3059123),('20190226',19976.01,'2000-0100','Saving',3059123),('20190225',20530.91,'2000-0100','Saving',3059123),('20190228',12345,'2000-1111','Senior Savings',4059123),('20190227',5456,'2000-1111','Senior Savings',4059123),('20190226',9999,'2000-1111','Senior Savings',4059123),('20190225',7893,'2000-1111','Senior Savings',4059123);
select b.AccountNo
,b.Product_Code
,b.Product_Description
,b.BalanceDate
,b.Balance
,r.Min_Range
,r.Max_Range
,r.Interest_Rate
,case when b.Balance > r.Max_Range
then r.Max_Range - r.Min_Range
else b.Balance - r.Min_Range
end as Split_Balance
,r.Interest_rate * case when b.Balance > r.Max_Range
then r.Max_Range - r.Min_Range
else b.Balance - r.Min_Range
end as Split_Balance_Interest
from #b as b
join #r as r
on b.Product_Code = r.Product_Code
and b.Balance > r.Min_Range
order by b.AccountNo
,b.BalanceDate;

ERROR: integer out of range In postgresql

Below is my table schema (I am using PostgreSQL 9.6.1)
my_table
------------
table_id SERIAL PRIMRY KEY,
A1 INTEGER,
A2 INTEGER,
A3 INTEGER,
A4 INTEGER,
A5 INTEGER,
A6 INTEGER,
A7 INTEGER,
A8 INTEGER,
A9 INTEGER,
A10 INTEGER,
A11 INTEGER,
A12 INTEGER,
A13 INTEGER,
A14 INTEGER,
A15 INTEGER,
A16 DOUBLE PRECISION,
A17 DOUBLE PRECISION
and i am trying to run below query in order to create a new table.
CREATE TABLE my_table_2 AS
SELECT
B1 AS C1
B3 AS C2,
B5 AS C3,
B7 AS C4 ,
B9 AS C5,
B11 AS C6 ,
B1 / CAST( NULLIF(B3, 0) AS FLOAT) AS C7,
B1 / CAST( NULLIF(B5, 0) AS FLOAT) AS C8,
B1 / CAST( NULLIF(B7, 0) AS FLOAT) AS C9,
B1 / CAST( NULLIF(B9, 0) AS FLOAT) AS C10,
B1 / CAST( NULLIF(B11, 0) AS FLOAT) AS C11,
B3 / CAST( NULLIF(B5, 0) AS FLOAT) AS C12,
B5 / CAST( NULLIF(B7, 0 )* NULLIF(B9,0) AS FLOAT) AS C13,
B2 AS C14 ,
B4 AS C15,
B6 AS C16,
B8 AS C17,
B10 AS C18,
B12 AS C19,
B2 / CAST(NULLIF(B4, 0) AS FLOAT) AS C20,
B2 / CAST(NULLIF(B6, 0) AS FLOAT) AS C21,
B2 / CAST(NULLIF(B8, 0) AS FLOAT) AS C22,
B2 / CAST(NULLIF(B10, 0) AS FLOAT) AS C23,
B2 / CAST(NULLIF(B12 , 0) AS FLOAT) AS C24
B4 / CAST(NULLIF(B6 , 0) AS FLOAT) AS C25
B6 / CAST(NULLIF(B8,0) * NULLIF( B10,0) AS FLOAT) AS C26
0.0 AS C27,
0.0 AS C28,
0.0 AS C29,
0.0 AS C30,
0.0 AS C31,
0.0 AS C32,
0.0 AS C33,
0.0 AS C34,
0.0 AS C35,
0.0 AS C36,
0.0 AS C37,
0.0 AS C38,
0.0 AS C39,
B13 AS C40
B14 AS C41,
B15 AS C42
FROM (
SELECT
table_id,
A1 - A2 + A3 AS B1,
A1 AS B2,
A4 - A5 AS B3,
A4 AS B4,
A6 - A7 AS B5,
A6 AS B6,
A8 - A9 AS B7,
A8 AS B8,
A10 - A11 AS B9,
A10 AS B10,
A12 - A13 AS B11,
A12 AS B12,
A14 AS B13,
A15 AS B14,
coalesce(coalesce(A16 * 100, 0) / NULLIF(A17, 0), 0) AS B15
FROM my_table
) v1;
I am running the above query as a background process using psql command
using below command
sudo -u postgres psql My_DB -X -a -f /tmp/test.sql > result.out 2>result.err &
Since my_table is a very huge table. But after sometime when I check result.err file. It has only one line saying
ERROR: integer out of range
For some sample ids in the WHere clause table gets generated without any issues but when i run it for entire table above error comes.
Can anyone explain why is this happening and how I can fix this?
Any of the + or - operations could cause this error, but the most likely cause is A16 * 100.
You can fix the problem by either avoiding operations that cause the overflow, or you could choose a data type like numeric or bigint that has a wider range of values.
check the multiplications
NULLIF(B7, 0 )* NULLIF(B9,0)
and
NULLIF(B8,0) * NULLIF( B10,0)
try to replace the order of calculation, the first division, then multiplication
( B5 / NULLIF(B7, 0) ) * NULLIF(B9,0) AS B15
( B6 / NULLIF(B8, 0) ) * NULLIF(B10,0) AS C26

PostgreSQL calculate percentage of current row's value over sum of totals

I group my data by seconditemid. Is it possible to calculate each row's percentage of sum(extcost) over the total sum (all table data's extcost combined)?
for example we have 2 rows in the result set, A1 has total of 4500, A2 has total of 5500, the grand total should be 10000 and A1 occupies 45%, A2 occupies 55%.
seconditemid|ratio
--------------------
A1 |.45
--------------------
A2 |.55
My query is
select seconditemid,
round(100.0*(
sum(case when seconditemid = ---the current row's seconditemid
then 1 else 0 end)/sum(extcost)
),1) as ratio
from inventory_fact f inner join item_master_dim i using (itemmasterkey)
where transtypekey = 1
group by seconditemid
order by 2 desc;
That does not work. I tried creating a view first
create view v1 as(
select sum(extcost) as sumExtcost from inventory_fact
);
and select from it
select seconditemid, round(100.0*(
sum(extcost)/sum(v1.sumextcost)
),1) as ratio
from from inventory_fact f inner join item_master_dim i using (itemmasterkey), v1
where transtypekey = 1
group by seconditemid
order by 2 desc;
then the ration of each column becomes 0.
Let's take this sample schema:
CREATE TABLE c (
seconditemid text,
total int
);
INSERT INTO c (seconditemid, total) VALUES ('A1', 4500);
INSERT INTO c (seconditemid, total) VALUES ('A2', 5500);
Here is the query:
SELECT seconditemid, total,
total::float / (SUM(total) OVER()) as ratio
FROM c;
->
seconditemid | total | ratio
--------------+-------+-------
A1 | 4500 | 0.45
A2 | 5500 | 0.55
(2 rows)
Your second query should be ok but you got 0s back because integer division truncates the results. You'd need to cast your sum values to floats explicitly.
Here is an example without the view
SELECT g.seconditemid, g.extcost::float / t.total::float percent -- << here
FROM (
SELECT seconditemid, SUM(extcost) extcost
FROM inventory_fact
GROUP BY seconditemid
) g CROSS JOIN (
SELECT SUM(extcost) total
FROM inventory_fact
) t
ORDER BY percent DESC
Output:
| seconditemid | percent |
|--------------|---------|
| A2 | 0.55 |
| A1 | 0.45 |
SQLFiddle