I have a table that I want to pivot, however the "key" is dynamic:
date
name
metric
8/1
foo
0.1
8/2
foo
0.2
8/3
foo
0.3
8/5
foo
0.5
8/1
bar
0.1
8/2
bar
0.2
8/3
bar
0.3
8/5
bar
0.5
And I want to show the last 2 available dates as columns
name
8/3
8/5
foo
0.3
0.5
bar
0.3
0.5
Is this possible?
Something like this doesn't work because it expects static keys:
SELECT
uid,
kv['c1'] AS c1,
kv['c2'] AS c2,
kv['c3'] AS c3
FROM (
SELECT uid, map_agg(key, value) kv
FROM vtable
GROUP BY uid
) t
if you don't mind having date value as column name , you can do this :
select name
,max(case when rn = 1 then metric end) LastMEtric
,max(case when rn = 2 then metric end) OneBeforeLastMetric
from (
select * , row_number() over (partition by name order by date desc) rn
from table
) t
group by name
Related
As shown on Table 1, I have a list of tenors and on Table 2 there is a list of cashflow times.
I would like to make a fully dynamic sheet and are using "#" referencing.
(1) the first tenor that is greater than the cashflow time column (as shown on result 2)
(2) the last value that is smaller than the cashflow time column (as shown on result 1).
Table 1
tenor
0
0.25
0.5
1
2
3
4
5
Table 2
cashflow time
result1
result2
-0.7392
n/a
0
0.1697
0
0.25
0.4216
0.25
0.5
0.6735
0.5
1
0.9253
0.5
1
1.1690
1
2
1.4209
1
2
For result1:
=XLOOKUP(C2:C8,A2:A9,A2:A9,,-1)
For result2:
=XLOOKUP(C2:C8,A2:A9,A2:A9,,1)
where C2:C8 are the cashflow time values nd A2:A9 are the tenor values.
I have a pandas dataframe, which looks like the following:
df =
a b
a1. 1
a2 0
a1 0
a3 1
a2 1
a1 1
I would like to first filter b on 1 and then, group by a and count number of times each group occurs (call this column count) and then attach this column with original df. b is guaranteed to be have at least one time 1 for each value of a.
Expected output:
df =
a b. count
a1. 1 2
a2 0. 1
a1 0. 2
a3 1 1
a2 1. 1
a1 1 2
I tried:
df['count] = df.groupby('a').b.transform('size')
But, this counts zeros as well. I want to filter for b == 1 first.
I also tried:
df['count'] = df[df['b' == 1].groupby('a').b.transform('size')
But, this introduces nans in the count column?
How can I do this in one line?
Check with get the condition apply to b then sum
df['b'].eq(1).groupby(df['a']).transform('sum')
Out[103]:
0 2.0
1 1.0
2 2.0
3 1.0
4 1.0
5 2.0
Name: b, dtype: float64
table:
var1 | var2
-----+------
0.5 | 19.99
var1 and var2 is double precision type
I know, that saved value could be 19.9900000000000000000000000001 or 19.989999999999999999999999999999999 (or 0.5 is not exact), but how to get the correct value (If the fractional part is exactly 0.5, rounding is upward for positive numbers and downward for negative numbers. - which comes from round definition):
SELECT var1, var2, round(var1*var2,2), round(0.5*19.99,2), round(9.995,2) FROM table
returns
var1 | var2 | this should be 10 | this is 10 | this is also 10
| | round(var1*var2,2)| round(0.5*19.99,2) | round(9.995,2)
-----+-------+-------------------+--------------------+-----------------
0.5 | 19.99 | 9.99 | 10 | 10
I tried round(round(var1,2)*round(var2,2)) but nothing changed
Literals like 0.5 and 19.99 are NUMERIC(18, 1) and NUMERIC(18, 2) respectively. The literal 0.5 * 19.99 is a NUMERIC(18, 3), which means the resulting value is exactly 9.995, which when rounded to 2 decimals will result in a NUMERIC(18, 3) value of 10.000.
On the other hand the same operations on double precision values are not precise. For example:
select
val1 * val2,
cast(val1 * val2 as varchar(100)),
round(val1 * val2, 2),
round(val1 * val2, 3),
round(round(val1 * val2, 3), 2),
round(val1 * val2 + 1e-10, 2)
from (
select
cast(0.5 as double precision) as val1,
cast(19.99 as double precision) as val2
from rdb$database) a
Will yield (in flamerobin), respectively:
9.995000 9.994999999999999 9.990000 9.995000 10.000000 10.000000
Where the first column being 9.995000 is a result of the rendering by flamerobin with max 6 decimals (as shown by the second column).
This may also hint at a solution: first round to a higher number of decimals, and then lower, or add a minor fraction like 1e-10, however this can still yield incorrect rounding with other values.
The same goes for converting the result to fixed point decimals: you will potentially introduce rounding errors somewhere.
the solution for now:
SELECT ROUND(CAST(var1 AS DECIMAL(9,2))*CAST(var2 AS DECIMAL(9,2)),2) FROM table
but maybe someone has better solution
I have the following table in excel:
0 1150 0.27
1151 1200 0.26
1201 1250 0.24
1251 1300 0.24
1301 1350 0.23
1351 1400 0.22
1401 1450 0.21
1451 1500 0.2
1501 1550 0.2
1551 1600 0.19
Now I am looking for a formula which is taking a value from a cell (I24), looks if it between the first and second value of the table and returns the third value. For example when the value of I24 is 1275 the formula should return 0.24
Here are few options
LookUp
= LookUp( I24, A:C )
This will work with your sample data, but like VLOOKUP it will compare only the values in the first column and will ignore the values in the second column. It will result in 0.19 for any value greater or equal to 1551, and in #N/A error for any value below 0.
SumProduct
= SumProduct( (A:A <= I24) * (I24 <= B:B) * C:C )
The result is the sum of all values that match the conditions, but in your case only one row will match the condition and the rest will result in 0.
Index and Match array formula
= Index( C:C, Match( 1, (A:A <= I24) * (I24 <= B:B), 0 ) )
This array formula solution has to be entered with Ctrl + Shift + Enter instead of just Enter. It will result in #N/A error for any value that is not in the range, so it can be combined with the IfError function to specify the value when there is no match:
= IfError( Index( C:C, Match( 1, (A:A <= I24) * (I24 <= B:B), 0 ) ), 1 )
Assuming your table starts on Column A and the value you mentioned is in I24:
=IF(AND(I24>A24,I24<B24),C24, "")
Use VLOOKUP:
=VLOOKUP(I24,A:C,3)
This will find where the value in I24 is greater than or equal to, and less than the next in Column A. Column B if it does not overlap Column As value is not needed.
I have a following reference table that I am using to extract the values
Table 1:
Name Jan Feb Mar Apr Total
John 0.1 0.2 0.3 0.4 1
Peter 0.2 0.4 0.6 0.3 1.5
Suman 0.1 0.3 0.2 0.5 1.1
into this table-
Table 2:
Name Month Value
John Feb
Peter Apr
Suman Jan
I need to match the text in "Name" column of Table 2 with the text in "Name" column in Table 1..and match the text in "Month" column of Table 2 with the Column Name itself in Table 1 to return the value for that particular column name
For example:
Match value "John" in Table 2 with value "John" in Table 1 Match value "Feb" in Table 2 with Column Name "Feb" in Table 2 to return the value 0.2 from Table 1
Can this be done using Index-Match using multiple criteria?
Assuming Table 1 starts in A1 and Table 2 starts in J1.
In Column L ("Value" column) starting in cell L2 place the formula:
=INDEX($A$1:$F$4,MATCH($J2,$A$1:$A$4,0),MATCH($K2,$A$1:$F$1,0))
And copy down to all relevant rows.
The first match selects the row for the index by matching the name and the second match selects the column by matching the month. Hope this helps. Cheers,