column Calculation if column > 1in T-SQL - tsql

hi i am trying to calculate a value of certain columns together and depending if a column is a certain value for instance
if lens.qty > 1 then (CASE LENS.LNS_PROGTYPE --DESIGN pOINTS
WHEN 762
THEN 70
when 767
THEN 70
when 768
THEN 70
WHEN 841
THEN 35
WHEN 842
then 35
else 0
end +
case LTRIM(RTRIM(LENS.COATTYP)) --ARC POINTS
when 'HVLL'
then 50
when 'HVLLBLUE'
then 100
else 0
end +
CASE LENS.LNS_IDX --MATERIAL POINTS
when 53
THEN 35
WHEN 56
THEN 35
WHEN 58
then 35
when 61
then 35
else 0
END +
CASE LENS.LNS_MATCLR --COLOR POINTS
WHEN 00
THEN 0
WHEN 46
THEN 35
WHEN 47
THEN 35
WHEN 48
then 35
else 0
end as TOTAL_POINTS)*lens.qty / 2
else
CASE LENS.LNS_PROGTYPE --DESIGN pOINTS
WHEN 762
THEN 70
when 767
THEN 70
when 768
THEN 70
WHEN 841
THEN 35
WHEN 842
then 35
else 0
end +
case LTRIM(RTRIM(LENS.COATTYP)) --ARC POINTS
when 'HVLL'
then 50
when 'HVLLBLUE'
then 100
else 0
end +
CASE LENS.LNS_IDX --MATERIAL POINTS
when 53
THEN 35
WHEN 56
THEN 35
WHEN 58
then 35
when 61
then 35
else 0
END +
CASE LENS.LNS_MATCLR --COLOR POINTS
WHEN 00
THEN 0
WHEN 46
THEN 35
WHEN 47
THEN 35
WHEN 48
then 35
else 0
end as TOTAL_POINTS)
i keep getting syntax error and i am not sure where i am going wrong
i am not sure how to do it and to be honest i don't completely understand the examples i have viewed your help would be greatly appreciated

I would do something like:
(CASE
WHEN LENS.LNS_PROGTYPE IN (762,767,768) THEN 70
WHEN LENS.LNS_PROGTYPE IN (841,842) THEN 35
else 0
end +
case LTRIM(RTRIM(LENS.COATTYP)) --ARC POINTS
when 'HVLL' then 50
when 'HVLLBLUE' then 100
else 0
end +
CASE
WHEN LENS.LNS_IDX IN (53,56,58,61) THEN 35
else 0
END +
CASE
WHEN LENS.LNS_MATCLR IN (46,47,48) THEN 35
else 0
end) * CASE WHEN lens.qty > 1 THEN lens.qty / 2 ELSE 1 END
For the entire expression. But, as I said, I'd also introduce some mapping tables rather than having all of these magic constants in the CASE expressions.

you must make sure, that all elements of that string/sum are of the same datatype. cast/convert them appropriately.

Related

How can I interrupt a 'loop' in kdb?

numb is a list of numbers:
q))input
42 58 74 51 63 23 41 40 43 16 64 29 35 37 30 3 34 33 25 14 4 39 66 49 69 13..
31 41 39 27 9 21 7 25 34 52 60 13 43 71 10 42 19 30 46 50 17 33 44 28 3 62..
15 57 4 55 3 28 14 21 35 29 52 1 50 10 39 70 43 53 46 68 40 27 13 69 20 49..
3 34 11 53 6 5 48 51 39 75 44 32 43 23 30 15 19 62 64 69 38 29 22 70 28 40..
18 30 60 56 12 3 47 46 63 19 59 34 69 65 26 61 50 67 8 71 70 44 39 16 29 45..
I want to iterate through each row and calculate the sum of the first 2 and then 3 and then 4 numbers etc. If that sum is greater than 1000 I want to stop the iteration on that particualr row and jump on the next row and do the same thing. This is my code:
{[input]
tot::tot+{[x;y]
if[1000<sum x;:count x;x,y]
}/[input;input]
}each numb
My problem here is that after the count of x is added to tot the over keeps going on the same row. How can I exit over and jump on the next row?
UPDATE: (QUESTION STILL OPEN) I do appreciate all the answers so far but I am not looking for an efficient way to sum the first n numbers. My question is how do I break the over and jump on the next line. I would like to achieve the same thing as with those small scripts:
C++
for (int i = 0; i <= 100; i++) {
if (i = 50) { printf("for loop exited at: %i ", i); break; }
}
Python
for i in range(100):
if i == 50:
print(i);
break;
R
for(i in 1:100){
if(i == 50){
print(i)
break
}
}
I think this is what you are trying to accomplish.
sum {(x & sums y) ? x}[1000] each input
It takes a cumulative sum of each row and takes an element wise minimum between that sum and the input limit thereby capping the output at the limit like so:
q)(100 & sums 40 43 16 64 29)
40 83 99 100 100
It then uses the ? operator to find the first occurance of that limit (i.e the element where this limit was equaled or passed) adding one as it is 0 indexed. In the example the first 100 occurs after 3 elements. You might want add one to include the first element after the limit in the count.
q)40 83 99 100 100 ? 100
3
And then it sums this count over all rows of the input.
You could use coverage in this case to exit when you fail to satisfy a condition
https://code.kx.com/q/ref/adverbs/#converge-repeat
The first parameter would be a function that does your check based on the current value of x which will be the next value to be passed in the main function.
For your example ive made a projection using the main input line then increase the indexes of what i am summing each time:
q)numb
98 11 42 97 89 80 73 35 4 30
86 33 38 86 26 15 83 71 21 22
23 43 41 80 56 11 22 28 47 57
q){[input] {x+1}/[{100>sum (y+1)#x}[input;];0] }each numb
1 1 2
this returns the first index of each where running sum is over 100
However this isn't really an ideal use case of KDB
could instead be done with something like
(sums#/:numb) binr\: 100
maybe your real example makes more sense
You can use while loops in KDB although all KDB developers are generally too afraid of being openly mocked and laughed at for doing so
q){i:0;while[i<>50;i+:1];:"loop exited at ",string i}`
"loop exited at 50"
Kdb does have a "stop loop" mechanism but only in the case of a monadic function with single seed value
/keep squaring until number is no longer less than 1000, starting at 2
q){x*x}/[{x<1000};2]
65536
/keep dealing random numbers under 20 until you get an 18 (seed value 0 is irrelevant)
q){first 1?20}\[18<>;0]
0 19 17 12 15 10 18
However this doesn't really fit your use case and as other people have pointed out, this is not how you would/should solve this problem in kdb.

MatLab Group by Non-Descending Order

In MatLab 2016b, is there a way to group the values of the below vector by non-descending order?
values = [1 1 1 7 17 74 89 91 96 1 5 32 43 78 84 95 98 100 0 0 15 31 69 88 94 97 100 100 100 0 2 12 42 66 78 83 89 94 97 1 6 34 63 65 75 89 93 98]
so I will get the following groups:
group A) 1 1 1 7 17 74 89 91 96
group B) 1 5 32 43 78 84 95 98 100
group C) 0 0 15 31 69 88 94 97 100 100 100
group D) 0 2 12 42 66 78 83 89 94 97
group E) 1 6 34 63 65 75 89 93 98
The following code should give you what you are looking for:
% Define the values...
values = [1 1 1 7 17 74 89 91 96 1 5 32 43 78 84 95 98 100 0 0 15 31 69 88 94 97 100 100 100 0 2 12 42 66 78 83 89 94 97 1 6 34 63 65 75 89 93 98];
% Define the linear indices...
subs = 1:numel(values);
% Define the grouping indices...
idx = [0 subs(diff(values) < 0) subs(end)];
% Split the values into multiple arrays...
result = arrayfun(#(k)values(idx(k-1)+1:idx(k)),2:numel(idx),'UniformOutput',false);
Here is the final output:
>> result{:}
ans =
1 1 1 7 17 74 89 91 96
ans =
1 5 32 43 78 84 95 98 100
ans =
0 0 15 31 69 88 94 97 100 100 100
ans =
0 2 12 42 66 78 83 89 94 97
ans =
1 6 34 63 65 75 89 93 98
diff(values)
returns a vector with the difference between each element of values and the following element. We can use this in a comparison to give a logical vector:
diff(values) < 0
returns a vector containing true, or 1, whenever the corresponding element of values is less than the following element. To finish the job we can use the cumsum function which returns a vector containing the running total of the elements in the input vector:
groups = cumsum([1, diff(values) < 0])
Just one wrinkle: we have to prepend an extra element at the front of the diff vector, because it has one fewer element than values did. Now we have a vector groups containing 1 for each element of values that should be in the first group, 2 for each element that should be in the second group, and so on.
You can access the individual groups using logical indexing:
values(groups == n) % returns a vector of the values in group n
If you want the groups as separate vectors you could use arrayfun:
groupArray = arrayfun(#(x) values(groups == x), 1:max(groups), 'UniformOutput', false)
This returns a cell array where groupArray{1} is the first group, groupArray{2} is the second group, etc.

read/load parts of the irregular file by Matlab

I would like to partly load a PTX file by matlab (please see the following example)
I need to read and write the first two row (2 numbers) into 2 variables say a and b. And read and write the data from 5th row to the end into a matrix
Thanks for your help
114
221
1 0 0
1 0 0 0
-5.566405 -7.161944 -1.144557 0.197208 24 29 35
-5.560656 -7.154540 -1.137673 0.222400 29 32 39
-5.559846 -7.153491 -1.131895 0.254002 37 40 49
-5.560894 -7.154833 -1.126452 0.305013 51 54 63
-5.560084 -7.153783 -1.120633 0.290013 72 76 88
-5.561128 -7.155119 -1.115189 0.243214 105 113 134
-5.563203 -7.157782 -1.109926 0.227604 130 143 177
-5.569191 -7.165479 -1.105504 0.201602 121 140 173
-7.833616 -10.078705 -1.546952 0.130007 94 112 134
Look at the tdfread function in order to get the data into Matlab. It should be something like datafile = tdfread(filename, '\t'). Once you have that, index into the variable returned from that function like
a = datafile(1, 1);
b = datafile(2, 1);
data = datafile(5:end, :);

Matlab: sum column elements with restrictions

We have a MxN matrix and a constrain cstrn = 100;.
The constrain is the summarize limit of column's elements (per column):
sum(matrix(:,:))<=cstrn.
For a given example as the following:
Columns 1 to 5:
15 18 -5 22 19
50 98 -15 39 -8
70 -15 80 45 38
31 52 9 80 72
-2 63 52 71 6
7 99 32 58 41
I want to find the max number of element per column who fulfill this constrain.
How can i summarize every column element with the others elements in same column and find which sum combinations uses the max number of elements per column?
In the given example solution is:
4 3 5 2 5
where
column 1: 15 + 50 + 31 +7 +(-2)
column 2: 18 +(-15) + 52 or 63 etc.
Thank you in advance.
Since it is always easier to fit small elements into a sum, you can do a sort, followed by the cumulative sum:
m= [
15 18 -5 22 19
50 98 -15 39 -8
70 -15 80 45 38
31 52 9 80 72
-2 63 52 71 6
7 99 32 58 41];
cs = cumsum(sort(m))
cs =
-2 -15 -15 22 -8
5 3 -20 61 -2
20 55 -11 106 17
51 118 21 164 55
101 216 73 235 96
171 315 153 315 168
Now you easily identify at which element you cross the threshold cnstrn (thanks, #sevenless)!
out = sum(cs <= cnstrn)
out =
4 3 5 2 5
I'd add to Jonas's answer, that you can impose your constraint in a way that outputs a logical matrix then sum over the 1's and 0's of that matrix like so:
cstrn = 100
m= [
15 18 -5 22 19
50 98 -15 39 -8
70 -15 80 45 38
31 52 9 80 72
-2 63 52 71 6
7 99 32 58 41];
val_matrix = cumsum(sort(m))
logical_matrix = val_matrix<=cstrn
output = sum(logical_matrix)
Giving output:
cstrn =
100
val_matrix =
-2 -15 -15 22 -8
5 3 -20 61 -2
20 55 -11 106 17
51 118 21 164 55
101 216 73 235 96
171 315 153 315 168
logical_matrix =
1 1 1 1 1
1 1 1 1 1
1 1 1 0 1
1 0 1 0 1
0 0 1 0 1
0 0 0 0 0
output =
4 3 5 2 5
Here is a logic, on mobile so can't give a code.
Check this out. Go to a column, sort it ascending order, loop to sum, break when hits <=100. Get counter. Refer back to original column, get the indices of elements matching the elements you just summed up :-)

MATLAB: extracting groups of columns into a submatrix?

I have a data-set, in which I want to extract columns 1-3, 7-9, 13-15, all the way to the end of the matrix
As an example, I've used the standard magic function to create a matrix
A=magic(10)
A =
92 99 1 8 15 67 74 51 58 40
98 80 7 14 16 73 55 57 64 41
4 81 88 20 22 54 56 63 70 47
85 87 19 21 3 60 62 69 71 28
86 93 25 2 9 61 68 75 52 34
17 24 76 83 90 42 49 26 33 65
23 5 82 89 91 48 30 32 39 66
79 6 13 95 97 29 31 38 45 72
10 12 94 96 78 35 37 44 46 53
11 18 100 77 84 36 43 50 27 59
I know that I can extract single columns starting at 1, in intervals of 3 with the command:
Aex=a(:,1 : 3 : end)
Aex =
92 8 74 40
98 14 55 41
4 20 56 47
85 21 62 28
86 2 68 34
17 83 49 65
23 89 30 66
79 95 31 72
10 96 37 53
11 77 43 59
Say I want to extract groups of columns instead (e.g. column 1-3, 7-9 etc.).
Is there a way to do this without having to manually point out all the column numbers?
Thanks for your help!
Rasmus
Is this what you are looking for:
Aex = A(:,[1:3 7:9])
?
I am assuming that you would like the result all concatenated into another large matrix?
If that is the case, try this one on for size:
result = A(diag(0:2)*ones(3,floor((size(A,2) - 3)/6) + 1) + ...
ones(3,floor((size(A,2) - 3)/6) + 1)*diag(1:6:(size(A,2)-3)))
That could probably be shortened with some matrix math rules. You could also parameterize the values so that it can be modified to do more than what this problem expects, (and also might make more sense),
a = 3;
b = 6;
result = A(diag(0:a-1)*ones(a,floor((size(A,2) - a)/b) + 1) + ...
ones(a,floor((size(A,2) - a)/b) + 1)*diag(1:b:(size(A,2)-a)))
where a is the size of "group" (length([1 2 3]) = length([7 8 9]) = ... = 3), etc. and b is the column spacing ([1...7...13...] in your example)
If you would like them separated, I put them in cells here, but they can go to wherever you need:
a = 3;
b = 6;
results = {};
for Cols = 1:b:(size(A,2)-a)
results{end+1} = A(:, Cols:(Cols+2));
end
I didn't check the speed of either of these, but I think the first one may be faster. You may want to split it up into terms so it's more readable, I just did it to fit on a single line (which isn't always the best way of writing code).
The simple way to do this:
M = magic(10);
n = size(M,2)
idx = sort([1:3:n 2:3:n 3:3:n])
M(:,idx)
If however, the pattern of removal is simpler than the pattern of colums that you want to keep you could use this instead:
A = magic(10);
B = A;
B(:,4:3:end)=[];
B(:,4:3:end)=[]; %Yes 3x the same line of code.
B(:,4:3:end)=[];