%let ng = 4;
data a1;
set a2;
array cur{&ng} cur1-cur&ng.;
do i = 1 to &ng.;
if (_n_ = (i-1)*5 + 1) then cur[i] = Val;
end;
run;
Error msg
ERROR: Missing numeric suffix on a numbered variable list (cur1-cur).
ERROR: Too few variables defined for the dimension(s) specified for the array cur.
ERROR 22-322: Syntax error, expecting one of the following: a name, (, ;, _ALL_, _CHARACTER_, _CHAR_, _NUMERIC_.
ERROR 200-322: The symbol is not recognized and will be ignored.
Why do i = 1 to &ng. and cur{&ng} work but cur1-cur&ng. generates errors?
That code works fine for me, however I have encountered this problem where I've created a macro variable (in this case ng) with the proc sql into: or call symput methods, as these set a default length of 8 and pad the value with spaces. I suspect in your actual code the macro variable ng is being created in one of these ways.
To get around this, try adding %trim as below.
array cur[&ng.] cur1-cur%trim(&ng.);
You also need to add an end statement to close the do loop.
Related
I am trying to perform a syntax analysis using bison, but it uses the wrong rule at one point and I didn't manage to find how to fix it.
I have a few rules but these ones seem to be the source of the problem :
method : vars statements;
vars : //empty
| vars var;
var : type IDENTIFIER ';';
type : IDENTIFIER;
statements : //empty
| statements statement;
statement : IDENTIFIER '=' e ';';
e : (...)
With IDENTIFIER being a simple regex matching [a-zA-Z]*
So basically, if I write that :
int myint;
myint = 12;
Since myint is an identifier, bison seems to still try to match it on the second line as a type and then matches the whole thing as a var and not as a statement. So I get this error (knowing that ASSIGN is '=') :
syntax error, unexpected ASSIGN, expecting IDENTIFIER
Edit : Note that bison is indicating that there are shift/reduce errors, so it may be linked (as said in the answers).
The problem you're having is coming from the default resolution of the shift-reduce conflict you have due to the empty statements rule -- it needs to know whether to reduce the empty statement and start matching statements, or shift the IDENTIFIER that might begin another var. So it decides to shift, which puts it down the var path.
You can avoid this problem by refactoring the grammar to avoid empty productions:
method: vars | vars statements | statements ;
vars: var | vars var ;
statements : statement | statements statement ;
... rest the same
which avoids needing to know whether something is var or a statement until after shifting far enough into it to tell.
I am a SAS novice. I am trying to convert character variables to numeric. The code below works for one variable, but I need to convert more than 50 variables, hopefully simultaneously. Would an array solve this problem? If so, how would I write the syntax?
DATA conversion_subset;
SET have;
new_var = input(oldvar,4.);
drop oldvar;
rename newvar=oldvar;
RUN;
#Reeza
DATA conversion_subset;
SET have;
Array old_var(*) $ a_20040102--a_20040303 a_302000--a_302202;
* The first list contains 8 variables. The second list contains 7 variables;
Array new_var(15) var1-var15;
Do i=1 to dim(old_var);
new_var(i) = input(old_var(i),4.);
End;
*drop a_20040102--a_20040303 a_302000--a_302202;
*rename var1-var15 = a_20040102--a_20040303 a_302000--a_302202;
RUN;
NOTE: Invalid argument to function INPUT at line 64 column 19
(new_var(i) = input(old_var(i),4.)
#Reeza
I am still stuck on this array. Your help would be greatly appreciated. My code:
DATA conversion_subset (DROP= _20040101 _20040201 _20040301);
SET replace_nulls;
Array _char(*) $ _200100--_601600;
Array _num(*) var1-var90;
Do i=1 to dim(_char);
_num(i) = input(_char(i),4.);
End;
RUN;
I am receiving the following error: ERROR: Array subscript out of range at line 64 column 6. Line 64 contains the input statement.
Yes, an array solves this issue. You will want a simple way to list the variables so look into SAS variable lists as well. For example if your converting all character variables between first and last you could list them as first_var-character-last_var.
The rename/drop are illustrated in other questions across SO.
DATA conversion_subset;
SET have;
Array old_var(50) $ first-character-last;
Array new_var(50) var1-var50;
Do i=1 to 50;
new_var(i) = input(oldvar(i),4.);
End;
RUN;
As #Parfait suggests, it would be best to adjust it when you are getting it, rather than after it is already in a SAS data set. However, if you're given the data set and have to convert that, that's what you have to do. You can add a WHERE clause to the PROC SQL to exclude variables that should not be converted. If you do so, they won't be in the final data set unless you add them in the CREATE TABLE's SELECT clause.
PROC CONTENTS DATA=have OUT=havelist NOPRINT ;
RUN ; %* get variable names ;
PROC SQL ;
SELECT 'INPUT(' || name || ',4.) AS ' || name
INTO :convert SEPARATED BY ','
FROM havelist
; %* create the select statement ;
CREATE TABLE conversion_subset AS
SELECT &convert
FROM have
;
QUIT ;
If excluding variables is an issue and/or you want to use a DATA step, then use the PROC CONTENTS above and follow with:
PROC SQL ;
SELECT COMPRESS(name || '_n=INPUT(' || name || ',4.)'),
COMPRESS(name || '_n=' || name),
COMPRESS(name)
INTO :convertlst SEPARATED BY ';',
:renamelst SEPARATED BY ' ',
:droplst SEPARATED BY ' '
FROM havelist
;
QUIT ;
DATA conversion_subset (RENAME=(&renamelst)) ;
SET have ;
&convertlst ;
DROP &droplst ;
RUN ;
Again, add a where clause to exclude variables that should not be converted. This will automatically preserve any variables that you exclude from conversion with a WHERE in the PROC SQL SELECT.
If you have too many variables, or their names are very long, or adding _n to the end causes a name collision, things can go badly (too much data for a macro variable, illegal field name, one field overwriting another, respectively).
After importing my CSV data with GETNAMES=NO, I have 59 columns with variable names VAR1, VAR2, . . . VAR59. My first row contains the names I need for the new variables, but they first needed manipulated by removing special characters and turning spaces into underscores since SAS doesn't like spaces in variable names. This is the array I used for that piece:
DATA DATA1; SET DATA (FIRSTOBS=7);
ARRAY VAR(59) VAR1-VAR59;
IF _N_ = 1 THEN DO;
DO I = 1 TO 59;
VAR[I] = COMPRESS(TRANSLATE(TRIM(VAR[I]),'_',' '),'?()');
PUT VAR[I]=;
END;
END;
DROP I;
RUN;
This worked perfectly, but now I need to get this first row up to the new variable names. I tried a similar array to perform this:
DATA DATA2; SET DATA1;
ARRAY V(59) VAR1-VAR59;
DO I = 1 TO 59;
IF _N_ = 1 AND V[I] NE "" THEN CALL SYMPUT("NEWNAME",V[I]);
RENAME VAR[I] = &NEWNAME;
END;
DROP I;
RUN;
This only puts the name of VAR59 since there is no [i] connected to the &NEWNAME, and it still isn't working quite right. Any suggestions to moving a row up to variable names AFTER manipulation?
Your primary problem is you are trying to use a macro variable in the data step it's created in. You can't. You're also trying to create rename statements in the data step; rename, as with other similar statements (keep, drop), must be defined before the data step is compiled.
You need to write code somewhere - either in a text file, a macro variable, whatever - with this information. For example:
filename renamef temp;
data _null_;
set myfile (obs=1);
file renamef;
array var[59];
do _i = 1 to dim(Var);
[your code to clean it out];
strput = cat("rename",vname(var[_i]),'=',var[_i],';');
put strput;
end;
run;
data want;
set myfile (firstobs=2);
%include renamef;
run;
There are lots of other examples to this on the site and on the web, "list processing" is the term for this.
Joe -- using your suggestions and another one of your posts, the following worked flawlessly:
Put the row of needed variables into long format (in my case, first row so n = 1)
DATA NEWVARS; SET DATA;
IF _N_ = 1 THEN OUTPUT NEWVARS;
RUN;
PROC TRANSPOSE DATA = NEWVARS OUT=NEWVARS1;
VAR _ALL_;
RUN;
Create a list of rename macro calls.
PROC SQL;
SELECT CATS('%RENAME(VAR=',_NAME_,',NEWVAR=',COL1,')')
INTO :RENAMELIST SEPARATED BY ' '
FROM NEWVARS1;
QUIT;
%MACRO RENAME(VAR=,NEWVAR=);
RENAME &VAR.=&NEWVAR.;
%MEND RENAME;
Call in the list created in Step 2 to rename all variables.
PROC DATASETS LIB=WORK NOLIST;
MODIFY DATA;
&RENAMELIST.;
QUIT;
I had to perform a few additional checks making sure that the variable names were not greater than 32 characters, and this was easy to check for when the data was in long format after transposing. If there are certain words that make the lengths too long, a TRANWRD statement can easily replace them with abbreviations.
I am trying to sum the contents of a postgresql array and also determine its length. In all cases, I am working with columns that are of integer array type.
ERROR: function sum(integer[]) does not exist
LINE 1: select sum(interested) from deals;
^
HINT: No function matches the given name and argument types. You might need to add explicit type casts.
db5=> select SUM(interested) from deals;
ERROR: function sum(integer[]) does not exist
LINE 1: select SUM(interested) from deals;
^
HINT: No function matches the given name and argument types. You might need to add explicit type casts.
db5=> select array_length(interested) from deals;
ERROR: function array_length(integer[]) does not exist
LINE 1: select array_length(interested) from deals;
^
HINT: No function matches the given name and argument types. You might need to add explicit type casts.
db5=>
Contrary to what I have read (Select sum of an array column in PostgreSQL, http://www.postgresql.org/docs/8.4/static/functions-array.html) sum(column) and array_length(column, 1) do not seem to perform as expected for me. Am I looking at the wrong docs? How can I get the sum and length of a postgre integer array?
Also, these are the php queries I am using along with pg_query to run these calls:
$query = "UPDATE deals set remaining = max - array_length(interested, 1), until = min -array_length(interested, 1";
$query = "UPDATE deals set remaining = max - (SELECT SUM FROM UNNEST(hours)), until = min - (SELECT SUM FROM UNNEST(hours))";
I modified them to take Patrick's suggestions from the comments into account, but I still get a syntax error, e.g.
Warning: pg_query(): Query failed: ERROR: syntax error at end of input LINE 1: ...ngth(interested, 1), until = min -array_length(interested, 1 ^ in /var/www/html/join.php on line 162
Thank you.
In the update statement you just forgot a bracket at end of the statement (see comment).
In the second update statement, you cannot use sum in UPDATE, because aggregate functions are not allowed in update.
Use a custom sql function which sums all elements in a array and use it in the update:
CREATE FUNCTION array_sum(NUMERIC[]) returns numeric AS
$$
SELECT sum(unnest) FROM (select unnest($1)) as foo;
$$
LANGUAGE sql;
The update statement:
UPDATE deals SET remaining = max - array_sum(hours), until = min - array_sum(hours);
I'm learning about Collections and trying out Associative Arrays in Oracle 11g. I'm using SQL Developer to write and test my code below and I am getting the error which I can't troubleshoot :
Error Report
Missing IN OUT Parameter at index ::1
Code I have written is as follows:
---SIMPLE collections EXAMPLE
DECLARE
TYPE prospect_towns IS TABLE OF VARCHAR2 (25)
INDEX BY PLS_INTEGER;
a_big_towns prospect_towns; -- associative array
i PLS_INTEGER := 1; -- index for the array
v_counter NUMBER;
v_town VARCHAR2(25);
BEGIN
a_big_towns(1):='Birmingham';
a_big_towns(2):='London':
a_big_towns(3):='Manchester';
-- v_counter := 1;
FOR i IN 1..a_big_towns.COUNT
LOOP <<big towns>>
--v_town := a_big_towns(i);
DBMS_OUTPUT.PUT_LINE('Inside Loop, town is '||a_big_towns(i));
i= a_big_towns.next:
END LOOP<<big towns>>
END;
/
Any ideas what's wrong ?
The second of these lines:
a_big_towns(1):='Birmingham';
a_big_towns(2):='London':
a_big_towns(3):='Manchester';
... has a colon at the end, instead of a semicolon. That's causing the following a_big_towns to be interpreted as a bind variable name by the parser. So it should be:
a_big_towns(2):='London';
Once you get past that, this line isn't needed, and would need := instead of = if it was, and also has a colon instead of a semicolon at the end:
i= a_big_towns.next:
... so remove that completely.
I'm not sure the labels are really adding anything here, but if you do have a label it doesn't need to be repeated at the end, and the name can't have a space in it, so make it:
<<big_towns>>
FOR i IN 1..a_big_towns.COUNT LOOP
And this needs a semicolon at the dned:
END LOOP;
This SQL Fiddle compiles.