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.
Related
I have the error "Error: duplicate case label", this is because i am using free pascal compiler, I have looked everywhere yet cannot find a solution, could you please provide me with one, thank you.
I will upload the full code in case there is something I am missing.
Sorry that it is messy.
program diceroll;
uses crt;
var count,time,double,dice1,dice2:integer;
sum1,sum2,sum3,sum4,sum5,sum6:integer;
idk:boolean;
Function Is_Double(d1,d2:integer):boolean;
begin
if d1 = d2 then
Is_Double:=true
else
Is_Double:=false;
end;
begin
randomize;
clrscr;
writeln('How many times do you want to roll the dice');
writeln(' ');
readln(time);
double:=0;
sum1:=0;
sum2:=0;
sum3:=0;
sum4:=0;
sum5:=0;
sum6:=0;
repeat
begin
dice1:=random(6)+1;
dice2:=random(6)+1;
idk:=Is_Double(dice1,dice2);
count:= count + 1;
if (idk = true) then
begin
double:= double + 1;
writeln(dice1,' ',dice2,' ','true');
end
else
writeln(dice1,' ',dice2,' ','true');
end;
if idk=true then
begin
case dice1 of
1:sum1:=sum1+1;
1:sum2:=sum2+1;
1:sum3:=sum3+1;
1:sum4:=sum4+1;
1:sum5:=sum5+1;
1:sum6:=sum6+1;
end;
until count = time;
writeln(double);
writeln(' ');
writeln(' ');
writeln(' ');
writeln(' ');
writeln(' Amount of doubles ');
writeln('1 2 3 4 5 6');
writeln(sum1,' ',sum2,' ',sum3,' ',sum4,' ',sum5,' ',sum6);
readln;
end.
Thank you
It's right here:
case dice1 of
1:sum1:=sum1+1;
1:sum2:=sum2+1;
1:sum3:=sum3+1;
1:sum4:=sum4+1;
1:sum5:=sum5+1;
1:sum6:=sum6+1;
It should be something like:
case dice1 of
1:sum1:=sum1+1;
2:sum2:=sum2+1;
3:sum3:=sum3+1;
4:sum4:=sum4+1;
5:sum5:=sum5+1;
6:sum6:=sum6+1;
Also your BEGIN... END structures look fishy to me:
repeat
// REPEAT doesn't need BEGIN
dice1:=random(6)+1;
dice2:=random(6)+1;
idk:=Is_Double(dice1,dice2);
count:= count + 1;
if (idk = true) then
begin
double:= double + 1;
writeln(dice1,' ',dice2,' ','true');
end
else
writeln(dice1,' ',dice2,' ','true');
// one extra END; removied - the one closing the unnecessory BEGIN at the start of REPEAT
if idk=true then
begin
case dice1 of
1:sum1:=sum1+1;
2:sum2:=sum2+1;
3:sum3:=sum3+1;
4:sum4:=sum4+1;
5:sum5:=sum5+1;
6:sum6:=sum6+1;
end; // CASE must have an END;
end;
until count = time;
I'd like to know how to use a function parameter conditionaly. This is my function, and you can read the comment inside the query:
CREATE OR REPLACE FUNCTION mediabase.select_media(sysEnvironment character varying, statusId integer)
RETURNS refcursor AS
$BODY$
DECLARE
ref refcursor;
BEGIN
OPEN ref FOR
SELECT media.id, media.title, media.unique_filename, media.owner_id, media.status_id, media.location_name_id, media.upload_user_id, media.upload_ip, media.metadata_id, media.type_id, media.description, media.system_environment, media.upload_date, media.gps_location, media.language_id, media_publications.publication_id, media.limitations, media_categories.category_id, metadata.width, metadata.height, metadata.equipment, metadata.copyright, metadata.creation_time, metadata.file_format, metadata.resolution, metadata.resolution_unit, metadata.gps_longitude, metadata.gps_latitude, metadata.artist, metadata.color_space, metadata.gps_altitude, metadata.software_used, metadata.user_comment
FROM mediabase.media, mediabase.metadata, mediabase.media_categories, mediabase.media_publications
WHERE media.metadata_id = metadata.id
AND media.id = media_categories.media_id
AND media.id = media_publications.media_id
-- Problem: this CASE doesn't work of course
CASE statusId <> -1 THEN
AND media.status_Id = statusId
END
-- End problem
AND media.system_environment = sysEnvironment
ORDER BY media.upload_date DESC;
RETURN ref;
END;
$BODY$
LANGUAGE plpgsql VOLATILE
COST 100;
I only need to use the 'statusId' parameter, if it's different from -1, otherwise I'll recieve no results as there of-course is no status -1. Later on, I'll need to add some more filters of that sort.
Try something like:
AND (media.status_Id = statusId OR statusId = -1)
It wont check media.status_Id = statusId if statusId = -1.
I need to find a way to dump key/value pairs of PL/pgSQL function input parameters:
CREATE OR REPLACE FUNCTION _test(A text, B text)
...
raise info 'Params dump: %', _x;
...
when executed:
select _text('HELLO', 'WORLD');
the function raises info as follows:
'A = HELLO, B = WORLD'
Is there a way to dump input parameter key/value pairs into a variable?
It's possible if you can make the function VARIADIC with uniform argument types, and can print the array. You don't get argument names, since they don't have names, but you do get argument positions.
Otherwise no, it is not possible in PL/PgSQL, though it should be in other PLs like PL/Perl, PL/Python, etc.
It'd be quite nice to be able to get a RECORD with all the function arguments in it, so you could print it, feed it to the hstore extension, etc, but this isn't currently possible.
There is an awkward way of dumping input parameters :
create or replace function _tester(
_txt text,
_int int
) returns void
language 'plpgsql' as
$$
declare
_out text = '';
_rec record;
_func_name text = '_tester';
begin
for _rec in SELECT parameters.ordinal_position as _pos, parameters.parameter_name as _nm
FROM information_schema.routines
JOIN information_schema.parameters
ON routines.specific_name=parameters.specific_name
WHERE routines.routine_name = _func_name
ORDER BY parameters.ordinal_position
loop
if _rec._pos = 1 then
_out = _out || _rec._nm || ' = ' || $1::text || chr(10);
elsif _rec._pos = 2 then
_out = _out || _rec._nm || ' = ' || $2::text || chr(10);
end if;
end loop;
raise notice '%', _out;
end;
$$;
select _tester('A','1');
NOTICE: _txt = A
_int = 1
Notice that must add as many if/elsif as there are input parameters. Not sure if that part can be more concise.
I like to return only the first number of a text stored in a column of a database table.
User have put in page ranges into a field like 'p.2-5' or 'page 2 to 5' or '2 - 5'.
I am interested in the '2' here.
I tried to
SELECT SUBSTR(the_field, LOCATE('2', the_field, 1)) AS 'the_number'
FROM the_table
and it works. But how to get ANY number?
I tried
SELECT SUBSTR(the_field, LOCATE(REGEXP '[0-9], the_field, 1)) AS 'the_number'
FROM the_table
but this time I get an error.
Any ideas?
Just use REGEXP_SUBSTR():
SELECT REGEXP_SUBSTR(`the_field`,'^[0-9]+') AS `the_number` FROM `the_table`;
Notes:
I'm using MySQL Server v8.0.
This pattern assumes that the_field is trimmed. Otherwise, use TRIM() first.
REGEXP is not a function in MySQL, but something of an operator. Returns 1 if field matches the regular expression, or 0 if it does not. You cannot use it to figure out a position in a string.
Usage:
mysql> SELECT 'Monty!' REGEXP '.*';
-> 1
As for answer to the question: I don't think there is a simple way to do that using MySQL only. You would be better off processing that field in the code, or extract values before inserting.
For the specific case in the question. Where the String is {number}{string}{number}
there is a simple solution to get the first number. In our case we had numbers like 1/2,3
4-10
1,2
and we were looking for the first number in each row.
It turned out that for this case one can use convert function to convert it into number. MySQL will return the first number
select convert(the_field ,SIGNED) as the_first_number from the_table
or more hard core will be
SELECT
the_field,
#num := CONVERT(the_field, SIGNED) AS cast_num,
SUBSTRING(the_field, 1, LOCATE(#num, the_field) + LENGTH(#num) - 1) AS num_part,
SUBSTRING(the_field, LOCATE(#num, the_field) + LENGTH(#num)) AS txt_part
FROM the_table;
This was original post at source by Eamon Daly
What does it do?
#num := CONVERT(the_field, SIGNED) AS cast_num # try to convert it into a number
SUBSTRING(the_field, 1, LOCATE(#num, the_field) + LENGTH(#num) - 1) # gets the number by using the length and the location of #num in field
SUBSTRING(the_field, LOCATE(#num, the_field) + LENGTH(#num)) # finds the rest of the string after the number.
Some thoughts for future use
Its worth keeping another column which will hold the first number after you parsed it before insert it to the database. Actually this is what we are doing these days.
Edit
Just saw that you have text like p.2-5 and etc.. which means the above cannot work as if the string does not start with a number convert return zero
There's no built-in way that I know of, but here's a Mysql function you can define, this will do it (I didn't code for minus-signs or non-integers, but those could of course be added).
Once created, you can use it like any other function:
SELECT firstNumber(the_field) from the_table;
Here's the code:
DELIMITER //
CREATE FUNCTION firstNumber(s TEXT)
RETURNS INTEGER
COMMENT 'Returns the first integer found in a string'
DETERMINISTIC
BEGIN
DECLARE token TEXT DEFAULT '';
DECLARE len INTEGER DEFAULT 0;
DECLARE ind INTEGER DEFAULT 0;
DECLARE thisChar CHAR(1) DEFAULT ' ';
SET len = CHAR_LENGTH(s);
SET ind = 1;
WHILE ind <= len DO
SET thisChar = SUBSTRING(s, ind, 1);
IF (ORD(thisChar) >= 48 AND ORD(thisChar) <= 57) THEN
SET token = CONCAT(token, thisChar);
ELSEIF token <> '' THEN
SET ind = len + 1;
END IF;
SET ind = ind + 1;
END WHILE;
IF token = '' THEN
RETURN 0;
END IF;
RETURN token;
END //
DELIMITER ;
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