Crystal Reports Error in formula - reporting-services

I have a global variable which was declared in a formula in the Report Header section of my document. I then try to reference that variable to use it in a for loop, and I get the error:
A number, currency amount, boolean,
data, time, date-time, or string is
expected here.
What is wrong here and how can I correct? Code follows:
Header Formula:
Global StringVar Array items;
redim items [1];
Global StringVar Array jobs;
redim jobs [1];
Global StringVar Array POs;
redim POs [1];
Global StringVar Array Qty;
redim Qty [1];
Global NumberVar numRecordsPrinted;
numRecordsPrinted := 0;
""
Detail Formula:
Local NumberVar occurances;
Local StringVar poTOuse;
Local NumberVar i;
if {%Line_PO_Test} <> ''
and {PackingSlipHeader.CompanyCode} <> '10063'
and {PackingSlipHeader.CompanyCode} <> '10017'
then
//Count the number of occurances
For i := 0 To numRecordsPrinted Do //Error on numRecordsPrinted
(
if items[i] = {PS_DETAIL_FOR_PRINT.DTSItemNumber}
AND jobs[i] = {PS_DETAIL_FOR_PRINT.JobNumber}
And Qty[i] = {PS_DETAIL_FOR_PRINT.Quantity_Shipped}
THEN
occurances := occurances + 1
)
//Use the # of occurances to get the right PO number
Select occurances
case 0: poTOuse := {#LinePOnum}
case 1: poTOuse := {#Line_PO_3}
case 2: poTOuse := {#Line_PO_2}
default: poTOuse := "";
//Save data into the array and increment for next time
numRecordsPrinted := numRecordsPrinted + 1
items[numRecordsPrinted] := {PS_DETAIL_FOR_PRINT.DTSItemNumber}
jobs[numRecordsPrinted] := {PS_DETAIL_FOR_PRINT.JobNumber}
Qty[numRecordsPrinted] := {PS_DETAIL_FOR_PRINT.Quantity_Shipped}
//Print to the report
'PO#: ' + poTOuse;

Surely this bit :
Select occurances
case 0: poTOuse = LinePOnum
case 1: poTOuse = Line_PO_3
case 2: poTOuse = Line_PO_2
default: poTOuse = "";
should be
Select occurances
case 0: poTOuse := LinePOnum
case 1: poTOuse := Line_PO_3
case 2: poTOuse := Line_PO_2
default: poTOuse := "";
Although it's not clear what LinePOnum, Line_PO_3 and Line_PO_2 are.

If you comment out the following section of code like so, do you still get an error?
For i := 0 To numRecordsPrinted Do //Error on numRecordsPrinted
(
// if items[i] = {PS_DETAIL_FOR_PRINT.DTSItemNumber}
// AND jobs[i] = {PS_DETAIL_FOR_PRINT.JobNumber}
// And Qty[i] = {PS_DETAIL_FOR_PRINT.Quantity_Shipped}
// THEN
occurances := occurances + 1
)
If yes, do you still get the error when you comment out occurances := occurances + 1?
Since the arrays are StringVars, you might need to wrap your database fields with cstr like this:
(
if items[i] = cstr({PS_DETAIL_FOR_PRINT.DTSItemNumber})
AND jobs[i] = cstr({PS_DETAIL_FOR_PRINT.JobNumber})
And Qty[i] = cstr({PS_DETAIL_FOR_PRINT.Quantity_Shipped})
THEN
occurances := occurances + 1
)
If you want to remove the trailing decimals for the Quantity_Shipped, you can use cstr({PS_DETAIL_FOR_PRINT.Quantity_Shipped}, "0") instead.

In crystal reports syntax, the variables have to be declared each time you use them. I wasn't aware that I have to declare the variables both in the header formula, and the detail formula. I made some other small syntax errors, but that was the main problem.
I didn't even consider this as a possibility because in most languages, declaring a variable more than once will cause the program to not even compile, let alone run.
Header Section
BeforeReadingRecords;
Global StringVar Array items;
Global StringVar Array jobs;
Global StringVar Array POs;
Global NumberVar Array Qty;
Global NumberVar numRecordsPrinted;
""
Detail Section
WhileReadingRecords;
Global StringVar Array items;
Global StringVar Array jobs;
Global StringVar Array POs;
Global NumberVar Array Qty;
Global NumberVar numRecordsPrinted;
Global NumberVar occurances;
occurances := 0;
Global StringVar poTOuse;
Global NumberVar i;
ReDim Preserve items[CDbl(Ubound(items) + 1)];
ReDim Preserve jobs[CDbl(Ubound(jobs) + 1)];
ReDim Preserve POs[CDbl(Ubound(POs) + 1)];
ReDim Preserve Qty[CDbl(Ubound(Qty) + 1)];
if {%Line_PO_Test} <> ""
and {PackingSlipHeader.CompanyCode} <> "10063"
and {PackingSlipHeader.CompanyCode} <> "10017"
then
//Count the number of occurances
For i := 1 To (numRecordsPrinted + 1) Do
(
if items[i] = {PS_DETAIL_FOR_PRINT.DTSItemNumber}
AND jobs[i] = {PS_DETAIL_FOR_PRINT.JobNumber}
And Qty[i] = {PS_DETAIL_FOR_PRINT.Quantity_Shipped}
THEN
occurances := occurances + 1
);
//Use the # of occurances to get the right PO number
Select occurances
case 0: poTOuse := {%Line_PO_Test}
case 1: poTOuse := {%Line_PO_3}
case 2: poTOuse := {%Line_PO_2}
default: poTOuse := "";
//Save data into the array and increment for next time
numRecordsPrinted := numRecordsPrinted + 1;
items[numRecordsPrinted] := {PS_DETAIL_FOR_PRINT.DTSItemNumber};
jobs[numRecordsPrinted] := {PS_DETAIL_FOR_PRINT.JobNumber};
Qty[numRecordsPrinted] := {PS_DETAIL_FOR_PRINT.Quantity_Shipped};
//Print to the report
if poTOuse <> "" THEN
'PO#: ' + poTOuse
ELSE
"";

I had a similar issue-- the " character in MS-Office is NOT the same thing as the MS-DOS " character. Save your formula in word as a strict MS-DOS .txt file and then copy-paste that into the CR formula editor. It's saved me before

Related

Pulling data in a for loop where data sometimes does not exist

Let's say I have four data values and one of them exists sometimes.
My For loop crashes because the path doesn't exist.
I would like to pass a "" in the cell instead of crashing.
myJSON.data[i].bank[0].money <- this part is my problem, because the bank[0].money sometimes doesn't exist.
I would like to keep the cell empty.
I tried an If but I didn't get it formatted properly, same goes for error handling.
Sub DATA()
Set RDict = CreateObject("Scripting.Dictionary")
Set dlist = CreateObject("Scripting.Dictionary")
JSON_String = Form.fromURL("exampleurl")
With CreateObject("htmlfile")
With .parentWindow
.execScript "var myJSON = " & JSON_String & ", csvstring = '';for (i = 0; i < myJSON.data.length; i++) {csvstring += myJSON.data[i].name + ',' + myJSON.data[i].bank[0].money + ',' + myJSON.data[i].location + ',' + myJSON.data[i].planneddate + ';';};"
RData = Split(.csvstring, ";")
End With
End With
For i = 0 To UBound(RData) - 1
DaData = Split(RData(i), ",")
If DaData(0) <> "null" Then RDict(DaData(0)) = DaData
Next i
Dim RSheet() As Variant
If RDict.Count > 0 Then
ReDim RSheet(2 To RDict.Count + 2, 1 To 7)
i = 0
For Each D In RDict
datalist(RDict(Da)(2)) = True
For j = 0 To 6
RSheet(i + 2, j + 1) = RDict(Da)(j)
Next j
i = i + 1
Next Da
RSData.Cells(2, 1).Resize(i, 6) = RSheet
End If
End Sub
You can handle null by using optional chaining with default nullish coalescing (#3 in example).
Something like this should work
Change myJSON.data[i]?.bank[0]?.money
To myJSON.data[i]?.bank[0]?.money ?? 'Unknown'
You can do the same with your other variables (myJSON.data[i].location and myJSON.data[i].planneddate) if they have the potential to be undefined or null as well
EDIT - Use Optional IF when optional chaining is not available
If that feature is not available in HTMLDocument's javascript maybe you can use basic conditional if?
This should work for undefined object, because undefined is == null
(myJSON.data[i].bank[0].money != null ? myJSON.data[i].bank[0].money : '-')

UPDATE multiple rows with different values in one query

I want to update multiple rows with different values, in one query. I know somehow this operation in SQL syntax. But implementing it into Go looks a bit confusing to me. For instance, I want to update the status column based on the menu_id column.
My code works for the first row but other rows value changes to null
updateSql := "UPDATE tb_menu SET tb_menu.status =( case" // set query statement
condition := " WHERE tb_menu.menu_id IN ("
menuList := []interface{}{} //set empty interface array
//counter := 0
for _, row := range status {
menuList = append(menuList, row.Menu_id, row.Status, row.Menu_id)
updateSql += (" WHEN tb_menu.menu_id = ? THEN ? ")
condition += "?,"
}
updateSql += "end)"
condition = strings.TrimSuffix(condition, ",") // remove last "," from query statement
condition += ") "
updateSql += condition
update, err := db.Prepare(updateSql)
if err != nil {
fmt.Println(" error occured on Preparedb function ", err)
res = false
defer db.Close()
return res
}
set, err := update.Exec(menuList...) // query data to db
if err != nil {
fmt.Println("error occured while updating menu list ", err)
res = false
defer db.Close()
return res
}

scannable barcode FONTS for SSRS report which can scan symbols too

There are basically two questions I'd like to ask here.
I have downloaded few fonts.(code 128, code-128 and free3to9 etc)
created report
took textBox
entered string like 123#123
set textbox font to downloaded few fonts.
In preview,
everything is fine. But when I try to read/scan generated barcode from preview,
In some case, it returns other fonts than 123#123
In some case, it doesn't scan the font.
So question is,
1). In SSRS report can we add scannable font which can scan symbols too and give exact and desire output?
If yes how and please let me know working font download link.
2). Only by downloading font and storing it to client and server would give desire out put?
I have checked this article which forces you to add .dll file and change some core files.
http://www.codeproject.com/Articles/789254/How-to-embed-Barcodes-in-your-SSRS-report
I followed this article and able to get the desired output. I could generate barcode in ssrs report and by exporting it to PDF, I'm able to scan it properly with symbols.
But this approach requires to copy .dll to
C:\Program Files\Microsoft SQL Server\MSRS10_50.MSSQLSERVER\Reporting Services\ReportServer\bin\
C:\Program Files (x86)\Microsoft Visual Studio 8\Common7\IDE\PrivateAssemblies
C:\Program Files (x86)\Microsoft Visual Studio 9\Common7\IDE\PrivateAssemblies
I did it and everything works as a charm.
But problem is I don't want to go with this approach as at server end I have to change some core files and copy .dll. I don't want to take such risk as high risk is associated with it.
so any other alternative way if someone has done it already.
For the font, we used Libre_Barcode_128
It needs to be installed for all users on the server running Reporting Services (right click the LibreBarcode128-Regular.ttf file, choose "Install for all users"). Then the reporting services box needs to be restarted (maybe you could just bounce the services, I just rebooted).
Then in the report, I changed the font to that. It produced barcodes, but those codes were not scannable. I had to change the field to:
=Code.StringToBarcode(Fields!Id.Value)
Then you right click in the black area around the report designer, and choose "Report Properties". Go to the Code tab, and paste this:
Public Shared Function StringToBarcode(ByVal value As String) As String
' Parameters : a string
' Return : a string which give the bar code when it is displayed with CODE128.TTF font
' : an empty string if the supplied parameter is no good
Dim charPos, minCharPos As Integer
Dim currentChar, checksum As Integer
Dim isTableB = True, isValid = True
Dim returnValue = String.Empty
If value.Length > 0 Then
' Check for valid characters
For charCount As Integer = 0 To value.Length - 1
'currentChar = char.GetNumericValue(value, charPos);
currentChar = Microsoft.VisualBasic.AscW(Char.Parse(value.Substring(charCount, 1)))
If Not (currentChar >= 32 AndAlso currentChar <= 126) Then
isValid = False
Exit For
End If
Next
' Barcode is full of ascii characters, we can now process it
If isValid Then
charPos = 0
While charPos < value.Length
If isTableB Then
' See if interesting to switch to table C
' yes for 4 digits at start or end, else if 6 digits
If charPos = 0 OrElse charPos + 4 = value.Length Then
minCharPos = 4
Else
minCharPos = 6
End If
minCharPos = IsNumber(value, charPos, minCharPos)
If minCharPos < 0 Then
' Choice table C
If charPos = 0 Then
' Starting with table C
returnValue = Microsoft.VisualBasic.ChrW(205).ToString() ' char.ConvertFromUtf32(205);
Else
' Switch to table C
returnValue = returnValue & Microsoft.VisualBasic.ChrW(199).ToString()
End If
isTableB = False
Else
If charPos = 0 Then
' Starting with table B
returnValue = Microsoft.VisualBasic.ChrW(204).ToString() ' char.ConvertFromUtf32(204);
End If
End If
End If
If Not isTableB Then
' We are on table C, try to process 2 digits
minCharPos = 2
minCharPos = IsNumber(value, charPos, minCharPos)
If minCharPos < 0 Then ' OK for 2 digits, process it
currentChar = Integer.Parse(value.Substring(charPos, 2))
currentChar = If(currentChar < 95, currentChar + 32, currentChar + 100)
returnValue = returnValue & Microsoft.VisualBasic.ChrW(currentChar).ToString()
charPos += 2
Else
' We haven't 2 digits, switch to table B
returnValue = returnValue & Microsoft.VisualBasic.ChrW(200).ToString()
isTableB = True
End If
End If
If isTableB Then
' Process 1 digit with table B
returnValue = returnValue & value.Substring(charPos, 1)
charPos += 1
End If
End While
' Calculation of the checksum
checksum = 0
For [loop] As Integer = 0 To returnValue.Length - 1
currentChar = Microsoft.VisualBasic.AscW(Char.Parse(returnValue.Substring([loop], 1)))
currentChar = If(currentChar < 127, currentChar - 32, currentChar - 100)
If [loop] = 0 Then
checksum = currentChar
Else
checksum = (checksum + [loop] * currentChar) Mod 103
End If
Next
' Calculation of the checksum ASCII code
checksum = If(checksum < 95, checksum + 32, checksum + 100)
' Add the checksum and the STOP
returnValue = returnValue & Microsoft.VisualBasic.ChrW(checksum).ToString() & Microsoft.VisualBasic.ChrW(206).ToString()
End If
End If
Return returnValue
End Function
Private Shared Function IsNumber(ByVal InputValue As String, ByVal CharPos As Integer, ByVal MinCharPos As Integer) As Integer
' if the MinCharPos characters from CharPos are numeric, then MinCharPos = -1
MinCharPos -= 1
If CharPos + MinCharPos < InputValue.Length Then
While MinCharPos >= 0
If Microsoft.VisualBasic.AscW(Char.Parse(InputValue.Substring(CharPos + MinCharPos, 1))) < 48 OrElse Microsoft.VisualBasic.AscW(Char.Parse(InputValue.Substring(CharPos + MinCharPos, 1))) > 57 Then
Exit While
End If
MinCharPos -= 1
End While
End If
Return MinCharPos
End Function
I believe I based this off of an article here:
code 128 barcode in c# wrong check digit for one barcode
Here is an code 128 encoder coded in T-SQL
You can easily add this new column (encoded text) to your sql result for your report
Then add textbox to your SSRS report and choose code 128 font. and VoilĂ  !
CREATE FUNCTION [Reporting].[Code128Encoder]
(
#TextToEncode NVARCHAR(255)
)
RETURNS NVARCHAR(255)
AS
BEGIN
--The following TSQL code will take a character string and perform the encoding
--that is necessary to generate a BARCODE 128 formatted string to be used with a BARCODE 128 font.
-- Define the string of characters that we'll need to pull the reference of
DECLARE #asciiString NVARCHAR(255)
SET #asciiString = ' !"#$%&''()*+,-./0123456789:;<=>?#ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~'
SET #asciiString = #asciiString + CHAR(195) -- 0xC3
SET #asciiString = #asciiString + CHAR(196) -- 0xC4
SET #asciiString = #asciiString + CHAR(197) -- 0xC5
SET #asciiString = #asciiString + CHAR(198) -- 0xC6
SET #asciiString = #asciiString + CHAR(199) -- 0xC7
SET #asciiString = #asciiString + CHAR(200) -- 0xC8
SET #asciiString = #asciiString + CHAR(201) -- 0xC9
SET #asciiString = #asciiString + CHAR(202) -- 0xCA
-- Define the stop and start characters
DECLARE #stopchar CHAR(1)
DECLARE #startchar CHAR(1)
DECLARE #spacechar CHAR(1)
SET #stopchar = CHAR(206) -- 0xCE
SET #startchar = CHAR(204) -- 0xCC
SET #spacechar = CHAR(194) -- 0xC2
-- Define the final holding place of our output string
DECLARE #finalArray NVARCHAR(255)
-- Define the variables that we'll need to be using
DECLARE #checksumTotal INT
DECLARE #checksum INT
SET #checksumTotal = 104;
SET #checksum = 0;
-- Start building our output
SET #finalArray = #startchar
-- Loop through our input variable and start pulling out stuff
DECLARE #position INT
DECLARE #thisChar CHAR(1)
SET #position = 1
WHILE #position <= LEN(#TextToEncode)
BEGIN
SET #thisChar = SUBSTRING(#TextToEncode, #position, 1)
SET #checksumTotal = #checksumTotal + (#position * (ASCII(#thischar)-32))
SET #finalArray = #finalArray + #thisChar
SET #position = #position + 1
END -- We've gone past the length now
-- Now we need to figure out and add the checksum character
SET #checksum = #checksumTotal % 103
IF #checksum = 0
SET #finalArray = #finalArray + #spacechar
ELSE
-- Barcorde array assumes 0 as initial offset so we need to add 1 to checksum
SET #finalArray = #finalArray + SUBSTRING(#asciiString, #checksum+1, 1)
-- Now we append the stop character
SET #finalArray = #finalArray + #stopchar
-- The #final Array represents the barcode encoded string
RETURN #finalArray
END

Query for replacing a number in string

In one Short Text column of a table such data was stored "any_text_N" where N is some number specific for each row.
I need to replace N by N+1.
Could any one provide query to do it?
Assuming (1) the number is always the rightmost characters, and (2) there is an underscore preceding the number, you can create a Function to parse the number and return the incremented value (see below).
Then to test it, create a query like follows (MAKE SURE YOU TEST FIRST!!!):
SELECT Table2.MyText, resetnbr([MyText]) AS NewVal
FROM Table2
WHERE (((Table2.MyText) Is Not Null));
Then to update your data:
UPDATE Table2 SET Table2.MyText= resetnbr([MyText])
WHERE (((Table2.MyText) Is Not Null));
Public Function ResetNbr(strIn As String) As String
'Assumes: (1) Number in rightmost position of string; (2) underscore preceeds number
Dim iLen As Integer
Dim i As Integer
Dim sNbr As String
If strIn = "" Then
ResetNbr = strIn
Exit Function
End If
iLen = Len(strIn)
For i = iLen To 1 Step -1
If Mid(strIn, i, 1) = "_" Then
Exit For
End If
Next i
If i > 1 Then
sNbr = Mid(strIn, i + 1, 99)
sNbr = sNbr + 1
ResetNbr = left(strIn, i) & sNbr
Else
' No underscore found!
ResetNbr = strIn
End If
End Function

Length Check In Pascal

I get the error Error: Operator is not overloaded on line 7. Do I have to do a another repeat and can't use the and operator?
Function GetValidPlayerName : String;
Var
PlayerName : String;
Begin
Repeat
Readln(PlayerName);
If PlayerName = '' And Length(PlayerName) > 10
Then Write('That was not a valid name. Please try again: ');
Until PlayerName <> '';
GetValidPlayerName := PlayerName;
End;
First, you need to write
If (PlayerName = '') And (Length(PlayerName) > 10) Then
The parentheses are required.
Secondly, this will always evaluate to false, because there is no string that is both empty and has length 11 or more. Indeed, a string is empty if and only if its length is zero, so basically you say "if the length is zero and the length is 11 or more, then...".
Most likely you wish instead to use a disjunction, that is, to use or instead of and:
If (PlayerName = '') Or (Length(PlayerName) > 10) Then
This will display the error message if the name is empty or if it is too long.
In addition, the loop will exit even if the name is invalid, because if PlayerName is equal to ThisIsATooLongName then indeed PlayerName <> ''.
What you need is something like
Function GetValidPlayerName : String;
Var
PlayerName : String;
Begin
Repeat
Readln(PlayerName);
If (PlayerName = '') Or (Length(PlayerName) > 10) Then
Begin
Write('That was not a valid name. Please try again: ');
PlayerName := '';
End;
Until PlayerName <> '';
GetValidPlayerName := PlayerName;
End;
or
Function GetValidPlayerName : String;
Var
PlayerName : String;
Begin
result := '';
Repeat
Readln(PlayerName);
If (PlayerName = '') Or (Length(PlayerName) > 10) Then
Write('That was not a valid name. Please try again: ')
Else
result := PlayerName;
Until result <> '';
End;
Urm Im in a similar situation,
while(Length(conversionrates[i].rate)<>2)) do
begin
writeln('the conversion name should be 2 letters. (E.G Pounds to Dollars would be "PD")');
readln(conversionrates[i].fromto);
end;
Wondering if this would work, the program I put this is wont compile.