How to update the column based on criteria in TSQL? - tsql

I have the following columns:
Cost | Rate1 | Rate2 | Rate3 | IsContainRate
100; 95; 100; 105; Y
105; 100; 110; 120; N
95; 95; 100; 130; Y
Basically, I want to update the IsContainRate column based on
IF (Cost = Rate1 OR Cost = Rate2 OR Cost=Rate3) THEN
update IsContainRate=Y
ELSE IsContainRate = N
Thanks

In TSQL, you can use a CASE statement to perform your conditional update.
Here's an example:
UPDATE yourTable
SET isContainRate = CASE
WHEN (Cost = Rate1
OR Cost = Rate2
OR Cost = Rate3)
THEN 'Y'
ELSE
'N'
END
The Case Statement will evaluate out to either 'Y' or 'N' depending on your expression.

Related

Left and right sides have a different number of elements when trying to define conditions of a periodic signal

I'm trying to plot periodic signal that has an exponent and time conditions, but I'm getting an error in my line one_period(-5 <= t1 & t1 < 0) = exp(10*t1 - 10);.
I'm still very new to MATLAB, so I'm unsure of how to fix this error.
T = 1;
t1 = linspace(0, T, 100 + 1);
t1(end) = [];
one_period = zeros(size(t1));
one_period(-5 <= t1 & t1 < 0) = exp(10*t1 - 10);
one_period(0 <= t1 & t1 < 5) = 10;
signal = repmat(one_period, 1, 5);
signal_length = 10;
t_signal_length = linspace(0, T*signal_length, signal_length*100 + 1);
t_signal_length(end) = [];
figure;
plot (t_signal_length, signal);
You are getting an error on this line:
one_period(-5 <= t1 & t1 < 0) = exp(10*t1 - 10);
Because t1 is defined as
T = 1;
t1 = linspace(0, T, 100 + 1);
t1(end) = [];
So it is an array between 0 and 1 with 101 elements, then with the last element removed.
And the condition you've used on the erroneous line is not satisfied for any element of t1, which values are you expecting to be between -5 and 0 in an array defined as values between 0 and 1?
Therefore this -5 <= t1 & t1 < 0 is an array where every value is false, i.e you are assigning into zero indices of one_period, but you are trying to assign something (on the right of the =) which has as many values as t1. One of these does not fit into the other!
MATLAB has pretty good debugging tools, which allow you to add breakpoints, run snippets of code whilst in debug, and view variables as the code progresses. You need to have a clear idea of your expected behaviour and then run through from a breakpoint to identify which part is failing.
If you had a different condition (which actually had some true values) then maybe you just need to use this index on both sides of the assignment so that the number of values matches the number of indicies. This would look something like
bValid = 0.5 <= t1 & t1 < 0.8; % some condition for a subset within (0,1)
one_period(bValid) = exp(10*t1(bValid) - 10); % Note indexing t1(bValid) too
T = 1; %-signal period
t1 = linspace(0, T, 100 + 1); %-time series from 0 to T
t1(end) = []; %-remove last value
one_period = zeros(size(t1)); %-make function array (all zeros)
one_period(0 <= t1 & t1 < 0.5) = exp(10*t1(0 <= t1 & t1 < 0.5) - 10); %-define the signal
one_period(0.5 <= t1 & t1 < 1) = exp(10*t1(0.5 <= t1 & t1 < 1) - 10);
signal_length = 5;
signal = repmat(one_period, 1, signal_length); %-replicate the signal 5 times
t_signal_length = linspace(0, T*signal_length, signal_length*100 + 1); %-replicate the time series
t_signal_length(end) = [];
figure; %plot
plot (t_signal_length, signal);
Example plot: https://imgur.com/a/XhZnqId
As always, comments are helpful for knowing what your intentions were but here's what I think you were trying to achieve.

Postgres custom aggregation returns null when parallelized

I have created a custom aggregate in postgres 11.3 and it works when parallel if off. When I mark it as parallel = safe, it returns null.
Could someone point me in the direction of where to start looking or how do I debug a parallel aggregation in postgres? In non parallel aggregation I can insert the state at each record into a temporary table, but inserts are not allowed in parallel queries...
Here's the aggregate:
CREATE OR REPLACE FUNCTION array_sort(ANYARRAY)
RETURNS ANYARRAY LANGUAGE SQL
AS $$
SELECT ARRAY(SELECT unnest($1) ORDER BY 1)
$$;
create type _stats_agg_accum_type AS (
cnt bigint,
q double precision[],
n double precision[],
np double precision[],
dn double precision[]
);
create type _stats_agg_result_type AS (
count bigint,
q25 double precision,
q50 double precision,
q75 double precision
);
create or replace function _stats_agg_p2_parabolic(_stats_agg_accum_type, double precision, double precision)
returns double precision AS '
DECLARE
a alias for $1;
i alias for $2;
d alias for $3;
BEGIN
RETURN a.q[i] + d / (a.n[i + 1] - a.n[i - 1]) * ((a.n[i] - a.n[i - 1] + d) * (a.q[i + 1] - a.q[i]) / (a.n[i + 1] - a.n[i]) + (a.n[i + 1] - a.n[i] - d) * (a.q[i] - a.q[i - 1]) / (a.n[i] - a.n[i - 1]));
END;
'
language plpgsql;
create or replace function _stats_agg_p2_linear(_stats_agg_accum_type, double precision, double precision)
returns double precision AS '
DECLARE
a alias for $1;
i alias for $2;
d alias for $3;
BEGIN
return a.q[i] + d * (a.q[i + d] - a.q[i]) / (a.n[i + d] - a.n[i]);
END;
'
language plpgsql;
create or replace function _stats_agg_accumulator(_stats_agg_accum_type, double precision)
returns _stats_agg_accum_type AS '
DECLARE
a ALIAS FOR $1;
x alias for $2;
k int;
d double precision;
qp double precision;
BEGIN
a.cnt = a.cnt + 1;
if a.cnt <= 5 then
a.q = array_append(a.q, x);
if a.cnt = 5 then
a.q = array_sort(a.q);
end if;
return a;
end if;
case
when x < a.q[1] then
a.q[1] = x;
k = 1;
when x >= a.q[1] and x < a.q[2] then
k = 1;
when x >= a.q[2] and x < a.q[3] then
k = 2;
when x >= a.q[3] and x < a.q[4] then
k = 3;
when x >= a.q[4] and x <= a.q[5] then
k = 4;
when x > a.q[5] then
a.q[5] = x;
k = 4;
end case;
for ii in 1..5 loop
if ii > k then
a.n[ii] = a.n[ii] + 1;
end if;
a.np[ii] = a.np[ii] + a.dn[ii];
end loop;
for ii in 2..4 loop
d = a.np[ii] - a.n[ii];
if (d >= 1 and a.n[ii+1] - a.n[ii] > 1) or (d <= -1 and a.n[ii-1] - a.n[ii] < -1) then
d = sign(d);
qp = _stats_agg_p2_parabolic(a, ii, d);
if qp > a.q[ii-1] and qp < a.q[ii+1] then
a.q[ii] = qp;
else
a.q[ii] = _stats_agg_p2_linear(a, ii, d);
end if;
a.n[ii] = a.n[ii] + d;
end if;
end loop;
return a;
END;
'
language plpgsql;
create or replace function _stats_agg_combiner(_stats_agg_accum_type, _stats_agg_accum_type)
returns _stats_agg_accum_type AS '
DECLARE
a alias for $1;
b alias for $2;
c _stats_agg_accum_type;
BEGIN
c.cnt = a.cnt + b.cnt;
c.q[2] = (a.q[2] + b.q[2]) / 2;
c.q[3] = (a.q[3] + b.q[3]) / 2;
c.q[4] = (a.q[4] + b.q[4]) / 2;
RETURN c;
END;
'
strict language plpgsql;
create or replace function _stats_agg_finalizer(_stats_agg_accum_type)
returns _stats_agg_result_type AS '
BEGIN
RETURN row(
$1.cnt,
$1.q[2],
$1.q[3],
$1.q[4]
);
END;
'
language plpgsql;
create aggregate stats_agg(double precision) (
sfunc = _stats_agg_accumulator,
stype = _stats_agg_accum_type,
finalfunc = _stats_agg_finalizer,
combinefunc = _stats_agg_combiner,
--parallel = safe,
initcond = '(0, {}, "{1,2,3,4,5}", "{1,2,3,4,5}", "{0,0.25,0.5,0.75,1}")'
);
Here's the setup and run code:
--CREATE TABLE temp (val double precision);
--insert into temp (val) select i from generate_series(0, 150000) as t(i);
select (stats_agg(val)).* from temp;
The expected result as follows and it works when run in parallel = unsafe
150001, 37500, 75000, 112500
In parallel = safe I get nulls:
150001, null, null, null
The problem is in the _stats_agg_combiner function. The function definition includes the strict keyword so there is no need to check for null input values.
In this specific aggregate, the _stats_agg_accum_type includes multiple arrays and the _stats_agg_combiner function requires that these arrays be filled with a minimum of 5 entries. This assumes that each new _stats_agg_accum_type instance processes at a minimum 5 records before being passed to the _stats_agg_combiner function.
Tests were being done on a table with 150k records and an assumption that each instance would therefore receive at a minimum 5 records. For whatever reason, this is an incorrect assumption. Regardless of the number of workers used (tested with 1-4) there is always at least one instance which processed exactly 0 records.
The solution was to add support for a _stats_agg_accum_type instance that had processed zero records and this had an array length of 0. See code below.
create or replace function _stats_agg_combiner(_stats_agg_accum_type, _stats_agg_accum_type)
returns _stats_agg_accum_type AS '
DECLARE
a alias for $1;
b alias for $2;
c _stats_agg_accum_type;
addA boolean;
addB boolean;
BEGIN
addA = a.cnt <= 5;
addB = b.cnt <= 5;
if addA and not addB then
c = b;
elsif addB and not addA then
c = a;
else
c.cnt = a.cnt + b.cnt;
for ii in 2..4 loop
c.q[ii] = (a.q[ii] + b.q[ii]) / 2;
end loop;
end if;
for ii in 1..5 loop
if addA and ii <= a.cnt then
c = _stats_agg_accumulator(c, a.q[ii]);
end if;
if addB and ii <= b.cnt then
c = _stats_agg_accumulator(c, b.q[ii]);
end if;
end loop;
RETURN c;
END;
'
language plpgsql strict;

Using for in a loop with different intervals

I have a for loop testing the max of a function:
function Start
max_i = 0;
max_j = 0;
max_value = 0;
for i =1:3500
for j = 1:3500
new_value = CalcUFamily(i,j);
if new_value > max_value;
max_value = new_value;
max_i = i;
max_j = j;
end
end
end
max_i
max_j
end
function uFamily = CalcUFamily(hh,hw) %h = male, w = wife
(code)
end
The basic is that it is testing a function that I have been trying to optimize (with some help from here) but which I have so far failed to do. I therefore want to test to make a loop that tests all possible values, work hours for a husband and a wife, from 1 h to 3500 h (yearly). I then want to get the highest utility value from CalcUFamily and its corresponding input variables, hh and hw (called i and j in the function above).
My code works well, apart from the fact that it takes too long to run since it runs 12 250 000 times. I therefore want to rase the test interval from 1 to 10 or maybe even 100. Is this possible with the for code, or do I have to rewrite it somehow?
Thanks a lot for your help!
Reshape CalcUFamily into a vector using colon (or reshape) and use max to find the maximum value (max_value) and its linear index. Now use ind2sub to convert this linear index into the equivalent row (hh or max_i) and column (hw or max_j) subscripts.
[max_value, max_Ind] = max(CalcUFamily(:));
[hh, hw] = ind2sub(size(CalcUFamily), max_Ind);
I found a solution myself! :)
max_hh = 0;
max_hw = 0;
max_value_hhhw = -50000;
max_value_u = -50000;
hh = 1;
hw = 1;
runs = 0;
interval = 10;
datestr(clock)
while hw < 3501
while hh < 3501 %runs hh to all posible values
new_value = CalcUFamily(hh,hw);
if new_value > max_value_u
max_value_hhhw = [hh hw]; %working hour husband, working hour wife, and its utility value
max_value_u = new_value;
end
hh = hh + interval;
runs = runs + 1; % number of runs
end
hh = 1;
hw = hw + interval;
end
runs
datestr(clock)
max_value_hhhw

Compute sum of series

I need to compute the sum of this series
I need the output this way:
If n = 3;
x = function_name(n)
I need to get x = 11.
If n = 5;
x = function_name(n)
I need to get x = 45.
I believe I need a for-loop to iterate; but am finding it difficult to iterate the increment value itself.
I guess you want the sum of the cumsum of the differences d of the numbers:
d = 2;
n = 5;
s = d:d:d*(n-1)
cs = cumsum( [1 s] )
scs = sum(cs)
%// or as anonymous function
scsh = #(n,d) sum( cumsum( [1 d:d:d*(n-1)] ) )
scs =
45
scsh(5,2) =
45
No need for a loop!
inc=2;
sum=1;
next=1;
n=input('what is n?\n');
for i=2:n
next=next+inc;
sum=sum+next;
inc=inc+2;
end
disp('sum is ');
disp(sum);
function Total = abc(n)
nth_term=1;
Total = 1 ;
for d = 2:2:(2*(n-1))
nth_term = nth_term + d;
Total =Total + nth_term;
end
end

index must be a positive integer or logical?

k = 0.019;
Pstar = 100;
H = 33;
h = 0.1;
X = 36;
N = round(X/h);
t = zeros(1,N+1);
P = zeros(1,N+1);
P(1) = 84;
t(1) = 0;
yHeun = zeros(1,N+1);
yHeun(1)=84;
a = 1; b = 100;
while b-a >0.5
c = (a+b)/2;
for n = 1:N
t(n+1) = t(n) + h;
Inside = nthroot(sin(2*pi*t/12),15);
Harvest = c*0.5*(Inside+1);
P(n+1) = P(n) + h*(k*P(n)*(Pstar-P(n))-Harvest(n));
if P < 0
P = 0;
end
yHeun(n+1) = yHeun(n) + h*0.5*((k*P(n)*(Pstar-P(n))-Harvest(n))+(k*P(n+1)*(Pstar-P(n+1))-Harvest(n+1)));
end
if sign(yHeun(c)) == sign(yHeun(a))
c = a;
else
c = b;
end
end
disp(['The root is between ' num2str(a) ' and ' num2str(b) '.'])
This is the code i'm trying to run and i know it probably sucks but im terrible at coding and every time i try to run the code, it says:
Attempted to access yHeun(50.5); index must be a positive integer or
logical.
Error in Matlab3Q4 (line 30)
if sign(yHeun(c)) == sign(yHeun(a))
I don't have ANY idea how to make yHeun(c or a or whatever) return anything that would be an integer. I dont think i did the while+for loop right either.
Question: "Begin with the higher bound of H being 100 (the high value results in a population of 0 after 36 months), and the lower bound being 1. Put the solver from Problem #3 above in the middle of a while loop and keep bisecting the higher and lower bounds of H until the difference between the higher and lower bound is less than 0.5."
I guess that line 30 (with the error) is this one:
if sign(yHeun(c)) == sign(yHeun(a))
Here, I guess c is equal to 50.5, as a result of c = (a+b)/2 above (BTW you can discover whether I guessed right by debugging - try adding disp(c) before line 30).
To force a number to be an integer, use floor:
c = floor((a+b)/2);
It seems you are trying to use some sort of divide-and-conquer algorithm; it should be enough to stop when b - a is equal to 1.