postgres - CASE evaluates any subexpression that is not needed to determine the result - postgresql

I have the following 3 examples of case expressions in postgres, which I would expect to evaluate in the same way. However the first and the third give ERROR: invalid input syntax for integer: "2017,7". The second one seems to be ok. Why is the difference?
Postgres documentation states
"A CASE expression does not evaluate any subexpressions that are not
needed to determine the result."
select case when 0 = 0 then 1 < 2
when 0 = 2 then ('2017.7')::bigint > 2000
end
(DB Fiddle)
select case when 0 = 0 then 1 < 2
when 0 = 2 then 2000 = ('2017.7'||'')::bigint
end
(DB Fiddle)
select case when (array[1,2])[1] =1 then 1 < 2
when (array[1,2])[1] = 2 then 2000 = ('2017.7'||'')::bigint
end
(DB Fiddle)

Related

How to run a formula until it meets a certain criteria?

So, I have a formula ( =INDEX(Sheet1.A1:F15,RANDBETWEEN(1,15),RANDBETWEEN(1,6)) ) that returns a random number in the sheet. But, how to run the formula until the returned number is less than or equal to 25 ?
I thought of using for..next.. but couldn't get it how to run ...
Welcome!
As #thebusybee pointed out in his comment, a macro for this task is much easier than using built-in functions. As rightly pointed out #tohuwawohu, pre-filtering the values makes things a lot easier. The macro code could be, for example, like this
Option Explicit
Function getRandValue(aValues As Variant, nTypeCriteria As Integer, dCriteriaValue As Variant) As Variant
Rem Params: aValues - array of values,
Rem nTypeCriteria - -2 less then, -1 not more, 0 equal, 1 not less, 2 more than
Rem dCriteriaValue - value to compare
Dim aTemp As Variant
Dim i As Long, j As Long, k As Long
Dim bGoodValue As Boolean
k = UBound(aValues,1)*UBound(aValues,2)
ReDim aTemp(1 To k)
k = 0
For i = 1 To UBound(aValues,1)
For j = 1 To UBound(aValues,2)
bGoodValue = False
Select Case nTypeCriteria
Case -2
bGoodValue = (aValues(i,j) < dCriteriaValue)
Case -1
bGoodValue = (aValues(i,j) <= dCriteriaValue)
Case 0
bGoodValue = (aValues(i,j) = dCriteriaValue)
Case 1
bGoodValue = (aValues(i,j) >= dCriteriaValue)
Case 2
bGoodValue = (aValues(i,j) > dCriteriaValue)
End Select
If bGoodValue Then
k = k+1
aTemp(k) = aValues(i,j)
EndIf
Next j
Next i
If k<1 Then
getRandValue = "No matching values"
ElseIf k=1 Then
getRandValue = aTemp(k)
Else
getRandValue = aTemp(Rnd()*(k-1)+1)
EndIf
End Function
Just put a call to this function in a cell in the form
=GETRANDVALUE(A1:F15;-1;25)

what formula can identify an ODD vs EVEN number

what formula can identify an ODD vs EVEN number
ODD result can be 0
EVEN result can be 1
or vice versa
The expression:
Mod ( YourNumber ; 2 )
returns 1 (True) if YourNumber is odd, 0 (False) otherwise.
The expression:
not Mod ( YourNumber ; 2 )
returns 1 (True) if YourNumber is even, 0 (False) otherwise.

Table sort by month

I have a table in MATLAB with attributes in the first three columns and data from the fourth column onwards. I was trying to sort the entire table based on the first three columns. However, one of the columns (Column C) contains months ('January', 'February' ...etc). The sortrows function would only let me choose 'ascend' or 'descend' but not a custom option to sort by month. Any help would be greatly appreciated. Below is the code I used.
sortrows(Table, {'Column A','Column B','Column C'} , {'ascend' , 'ascend' , '???' } )
As #AnonSubmitter85 suggested, the best thing you can do is to convert your month names to numeric values from 1 (January) to 12 (December) as follows:
c = {
7 1 'February';
1 0 'April';
2 1 'December';
2 1 'January';
5 1 'January';
};
t = cell2table(c,'VariableNames',{'ColumnA' 'ColumnB' 'ColumnC'});
t.ColumnC = month(datenum(t.ColumnC,'mmmm'));
This will facilitate the access to a standard sorting criterion for your ColumnC too (in this example, ascending):
t = sortrows(t,{'ColumnA' 'ColumnB' 'ColumnC'},{'ascend', 'ascend', 'ascend'});
If, for any reason that is unknown to us, you are forced to keep your months as literals, you can use a workaround that consists in sorting a clone of the table using the approach described above, and then applying to it the resulting indices:
c = {
7 1 'February';
1 0 'April';
2 1 'December';
2 1 'January';
5 1 'January';
};
t_original = cell2table(c,'VariableNames',{'ColumnA' 'ColumnB' 'ColumnC'});
t_clone = t_original;
t_clone.ColumnC = month(datenum(t_clone.ColumnC,'mmmm'));
[~,idx] = sortrows(t_clone,{'ColumnA' 'ColumnB' 'ColumnC'},{'ascend', 'ascend', 'ascend'});
t_original = t_original(idx,:);

Compute the Frequency of bigrams in Matlab

I am trying to compute and plot the distribution of bigrams frequencies
First I did generate all possible bigrams which gives 1296 bigrams
then i extract the bigrams from a given file and save them in words1
my question is how to compute the frequency of these 1296 bigrams for the file a.txt?
if there are some bigrams did not appear at all in the file, then their frequencies should be zero
a.txt is any text file
clear
clc
%************create bigrams 1296 ***************************************
chars ='1234567890abcdefghijklmonpqrstuvwxyz';
chars1 ='1234567890abcdefghijklmonpqrstuvwxyz';
bigram='';
for i=1:36
for j=1:36
bigram = sprintf('%s%s%s',bigram,chars(i),chars1(j));
end
end
temp1 = regexp(bigram, sprintf('\\w{1,%d}', 1), 'match');
temp2 = cellfun(#(x,y) [x '' y],temp1(1:end-1)', temp1(2:end)','un',0);
bigrams = temp2;
bigrams = unique(bigrams);
bigrams = rot90(bigrams);
bigram = char(bigrams(1:end));
all_bigrams_len = length(bigrams);
clear temp temp1 temp2 i j chars1 chars;
%****** 1. Cleaning Data ******************************
collection = fileread('e:\a.txt');
collection = regexprep(collection,'<.*?>','');
collection = lower(collection);
collection = regexprep(collection,'\W','');
collection = strtrim(regexprep(collection,'\s*',''));
%*******************************************************
temp = regexp(collection, sprintf('\\w{1,%d}', 1), 'match');
temp2 = cellfun(#(x,y) [x '' y],temp(1:end-1)', temp(2:end)','un',0);
words1 = rot90(temp2);
%*******************************************************
words1_len = length(words1);
vocab1 = unique(words1);
vocab_len1 = length(vocab1);
[vocab1,void1,index1] = unique(words1);
frequencies1 = hist(index1,vocab_len1);
I. Character counting problem for a string
bsxfun based solution for counting characters -
counts = sum(bsxfun(#eq,[string1-0]',65:90))
Output -
counts =
2 0 0 0 0 2 0 1 0 0 ....
If you would like to get a tabulate output of counts against each letter -
out = [cellstr(['A':'Z']') num2cell(counts)']
Output -
out =
'A' [2]
'B' [0]
'C' [0]
'D' [0]
'E' [0]
'F' [2]
'G' [0]
'H' [1]
'I' [0]
....
Please note that this was a case-sensitive counting for upper-case letters.
For a lower-case letter counting, use this edit to this earlier code -
counts = sum(bsxfun(#eq,[string1-0]',97:122))
For a case insensitive counting, use this -
counts = sum(bsxfun(#eq,[upper(string1)-0]',65:90))
II. Bigram counting case
Let us suppose that you have all the possible bigrams saved in a 1D cell array bigrams1 and the incoming bigrams from the file are saved into another cell array words1. Let us also assume certain values in them for demonstration -
bigrams1 = {
'ar';
'de';
'c3';
'd1';
'ry';
't1';
'p1'}
words1 = {
'de';
'c3';
'd1';
'r9';
'yy';
'de';
'ry';
'de';
'dd';
'd1'}
Now, you can get the counts of the bigrams from words1 that are present in bigrams1 with this code -
[~,~,ind] = unique(vertcat(bigrams1,words1));
bigrams_lb = ind(1:numel(bigrams1)); %// label bigrams1
words1_lb = ind(numel(bigrams1)+1:end); %// label words1
counts = sum(bsxfun(#eq,bigrams_lb,words1_lb'),2)
out = [bigrams1 num2cell(counts)]
The output on code run is -
out =
'ar' [0]
'de' [3]
'c3' [1]
'd1' [2]
'ry' [1]
't1' [0]
'p1' [0]
The result shows that - First element ar from the list of all possible bigrams has no find in words1 ; second element de has three occurrences in words1 and so on.
Hey similar to Dennis solution you can just use histc()
string1 = 'ASHRAFF'
histc(string1,'ABCDEFGHIJKLMNOPQRSTUVWXYZ')
this checks the number of entries in the bins defined by the string 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' which is hopefully the alphabet (just wrote it fast so no garantee). The result is:
Columns 1 through 21
2 0 0 0 0 2 0 1 0 0 0 0 0 0 0 0 0 1 1 0 0
Columns 22 through 26
0 0 0 0 0
Just a little modification of my solution:
string1 = 'ASHRAFF'
alphabet1='A':'Z'; %%// as stated by Oleg Komarov
data=histc(string1,alphabet1);
results=cell(2,26);
for k=1:26
results{1,k}= alphabet1(k);
results{2,k}= data(k);
end
If you look at results now you can easily check rather it works or not :D
This answer creates all bigrams, loads in the file does a little cleanup, ans then uses a combination of unique and histc to count the rows
Generate all Bigrams
note the order here is important as unique will sort the array so this way it is created presorted so the output matches expectation;
[y,x] = ndgrid(['0':'9','a':'z']);
allBigrams = [x(:),y(:)];
Read The File
this removes capitalisation and just pulls out any 0-9 or a-z character then creates a column vector of these
fileText = lower(fileread('d:\loremipsum.txt'));
cleanText = regexp(fileText,'([a-z0-9])','tokens');
cleanText = cell2mat(vertcat(cleanText{:}));
create bigrams from file by shifting by one and concatenating
fileBigrams = [cleanText(1:end-1),cleanText(2:end)];
Get Counts
the set of all bigrams is added to our set (so the values are created for all possible). Then a value ∈{1,2,...,1296} is assigned to each unique row using unique's 3rd output. Counts are then created with histc with the bins equal to the set of values from unique's output, 1 is subtracted from each bin to remove the complete set bigrams we added
[~,~,c] = unique([fileBigrams;allBigrams],'rows');
counts = histc(c,1:1296)-1;
Display
to view counts against text
[allBigrams, counts+'0']
or for something potentially more useful...
[sortedCounts,sortInd] = sort(counts,'descend');
[allBigrams(sortInd,:), sortedCounts+'0']
ans =
or9
at8
re8
in7
ol7
te7
do6 ...
Did not look into the entire code fragment, but from the example at the top of your question, I think you are looking to make a histogram:
string1 = 'ASHRAFF'
nr = histc(string1,'A':'Z')
Will give you:
2 0 0 0 0 2 0 1 0 0 0 0 0 0 0 0 0 1 1 0 0 0 0 0 0 0 0
(Got a working solution with hist, but as #The Minion shows histc is more easy to use here.)
Note that this solution only deals with upper case letters.
You may want to do something like so if you want to put lower case letters in their correct bin:
string1 = 'ASHRAFF'
nr = histc(upper(string1),'A':'Z')
Or if you want them to be shown separately:
string1 = 'ASHRaFf'
nr = histc(upper(string1),['a':'z' 'A':'Z'])
bi_freq1 = zeros(1,all_bigrams_len);
for k=1: vocab_len1
for i=1:all_bigrams_len
if char(vocab1(k)) == char(bigrams(i))
bi_freq1(i) = frequencies1(k);
end
end
end

crystal reports conditional formatting for summary fields

I'm trying to create a decimal formatting formula on my summary fields. The values in the database could have 0, 1, or 2 decimal places. I've started with this:
If (CurrentFieldValue mod 1 = 0) Then
0
Else If (CurrentFieldValue mod .1 = 0) Then
1
Else
2
On a simple single data field, this works and displays the value with 0, 1, or 2 decimal places based on the data coming from my database. The same formula doesn't work for a summary field on my reports with group data. Any ideas?
Edit: Since I don't know how to format code in a comment, I'll address the suggestion of using a formula here:
Didn't work. Formula:
Sum ({myTable.dataValue}, {myTable.groupField})
then I used:
If ({#formula} mod 1 = 0) Then
0
Else If ({#formula} mod .1 = 0) Then
1
Else
2
And I still got whole numbers for everything. My rounding is set to .01 with no formula. Do I need a formula for rounding too? I still don't understand why this works on individual values but not for group summaries.
OK- it turns out this is due to our lack of understanding of the mod function :)
Everything mod 1 actually returns 0. This is the formula you need to use:
if {ER100_ACCT_ORDER.ER100_ORD_TOT} * 100 mod 100 = 0 then
0
else if {ER100_ACCT_ORDER.ER100_ORD_TOT} * 100 mod 10 = 0 then
1
else
2
:)
How about just creating a formula field instead of using the built-in summary field:
sum({mytable.myfield})
Then you can use your conditional formatting:
If ({#formula} mod 1 = 0) Then
0
Else If ({#formula} mod .1 = 0) Then
1
Else
2