I am trying to write a PL/SQL function name hoursWorked that takes workerId and prjId and returns total amount of hours worker has worked on a project.
Table named PROJECTHOURS
WORKERPRJID | WORKERID | PRJID | TOTHOURS | CDATE
---------- ---------- ---------- ---------- ---------
1 1 1 10 1-JAN-14
2 1 1 7 2-JAN-14
3 1 1 6 4-JAN-14
4 2 1 5 11-JAN-14
5 2 1 9 15-JAN-14
6 2 1 7 13-JAN-14
7 1 2 5 11-JAN-14
8 2 2 9 15-JAN-14
9 2 2 7 13-JAN-14
I have tried the following:
CREATE OR replace PROCEDURE Hoursworked (j IN NUMBER,
n IN NUMBER)
IS
hours_worked projecthours.tothours%TYPE := 0;
BEGIN
SELECT workerid,
prjid,
SUM(tothours)
INTO hours_worked
FROM projecthours
WHERE workerid = j
AND prjid = n
GROUP BY j,
n;
RETURN hours_worked;
END;
SQL> show errors;
Errors for PROCEDURE HOURSWORKED:
LINE/COL ERROR
-------- -----------------------------------------------------------------
6/1 PL/SQL: SQL Statement ignored
6/52 PL/SQL: ORA-00947: not enough values
12/1 PL/SQL: Statement ignored
12/1 PLS-00372: In a procedure, RETURN statement cannot contain an
expression
Admittedly I am very inexperienced with SQL in general, so any insights are very welcome, as to what I am doing wrong.
The select is wrong, you select 3 values, but fetch into only one. The group by references are incorrect.
You don't need to select the workerid or the project id, neither do you need the group by.
Should be like below
CREATE OR replace PROCEDURE Hoursworked (j IN NUMBER,
n IN NUMBER,
hours_worked OUT NUMBER)
IS
BEGIN
SELECT SUM(tothours)
INTO hours_worked
FROM projecthours
WHERE workerid = j
AND prjid = n;
END;
In a procedure Return immediately ends program execution, and doesn't expect any parameters. Either change the program unit type to a function, or use OUT variables as above.
And please give better parameter names than "j" & "n"
Related
given scenario,
id name sequence
1 a 1
2 b 2
3 c 3
4 d 4
5 e 5
User table has sequence which represent the order of users to display in the front end.
in the above example if I try to insert a user in between user id 3, then the expected behaviour should be
id name sequence
1 a 1
2 b 2
3 c 3
4 d 5
5 e 6
6 f 4
here position calculated using the last sequence input
last_sequence = 3.
Similarly, the user can repeat the same kind of operation, and it should be reordered according to in the database.
Note: not JQuery sorting.
My try
seq = last_sequence
users.where("last_sequence >= ? and id != ?",3,6).each do |u|
u.update_attributes(sequence: seq+1 )
seq = u.sequence + 1
end
I know the above is wrong and wrapping my head to find a solution
I resolved like the below
seq = latest_updated_user.sequence
user.where("sequence >= ? and id != ?",last_user.sequence, last_user.id).order(:sequence, :created_at).each do |v|
v.update_attributes(sequence: seq)
seq += 1
end
I am very new to SQL and PL/SQL. I am writing a procedure to take a museum, average the price of art, then increase the average by a percent. The user enters the museum ID (musmID) and percent increase. If the percent is too high there is an exception raised. If the musmID entered does not match one on the table, an exception is raised. Output is museum name, old avg price, and new avg price. So far it will only work when the exception for invalid musmID is not written. I keep getting the same error of PLS-00201:identifier 'MUMSID' must be declared.
Table 1 is arts and column names are musmID(FK) and price.
Table 2 is museums and column names are museum and musmID(PK).
My code:
CREATE OR REPLACE PROCEDURE proc_second (p_musmID IN arts.musmID%TYPE,
p_percent IN NUMBER) IS
v_musmID arts.musmID%TYPE;
v_oldavg arts.price%TYPE;
v_newavg arts.price%TYPE;
v_musmName museums.museum%TYPE;
too_high EXCEPTION;
musmID_invalid EXCEPTION;
BEGIN
IF p_percent > 40 THEN
raise too_high;
END IF;
IF musmID != p_musmID THEN
raise musmID_invalid;
END IF;
SELECT musmID, AVG(price) INTO v_musmID, v_oldavg from arts
WHERE musmID = p_musmID
GROUP BY musmID;
SELECT museum INTO v_musmName from museums
WHERE musmId = p_musmID;
v_newavg := v_oldavg * (1 + (p_percent/100));
dbms_output.put_line (v_musmname || ' ' || v_oldavg || ' ' || v_newavg);
EXCEPTION
WHEN too_high THEN
dbms_output.put_line ('Specify less than 40 percent increase');
WHEN musmID_invalid THEN
dbms_output.put_line ('You entered an invalid museum ID');
END;
/
Warning: Procedure created with compilation errors.
These are the errors i am getting.
LINE/COL ERROR
-------- -----------------------------------------------------------------
15/3 PL/SQL: Statement ignored
15/6 PLS-00201: identifier 'MUSMID' must be declared
I know it is probably something basic i am not seeing but so far if i get rid of the errors, the procedure raises the musmID_invalid exception no matter what is entered.
Huh. This code is wrongly arranged, as far as I can tell. You're first checking a variable, and then fetch its value.
I've created two dummy tables, just to make the procedure compile.
SQL> create table arts
2 (musmid number,
3 price number);
Table created.
SQL> create table museums
2 (musmid number,
3 museum number);
Table created.
Now, the procedure: it seems that you don't need V_MUSMID variable at all, because it is equal to P_MUSMID parameter (see the SELECT which selects the AVG(PRICE) and its WHERE clause). It means that you can use P_MUSMID throughout the code, instead of V_MUSMID.
It also means that MUSMID_INVALID will never be raised; you should, though, handle the NO_DATA_FOUND which will be raised if you pass a non-existent P_MUSMID.
So, I removed what I thought you don't need and - this is the remaining code; see if it does any good.
SQL> create or replace procedure proc_second (p_musmid in arts.musmid%type,
2 p_percent in number)
3 is
4 v_oldavg arts.price%type;
5 v_newavg arts.price%type;
6 v_musmname museums.museum%type;
7 too_high exception;
8 begin
9 if p_percent > 40 then
10 raise too_high;
11 end if;
12
13 select m.museum, avg(a.price)
14 into v_musmname, v_oldavg
15 from arts a join museums m on m.musmid = a.musmid
16 where a.musmid = p_musmid
17 group by m.museum;
18
19 v_newavg := v_oldavg * (1 + (p_percent/100));
20
21 dbms_output.put_line (v_musmname || ' ' || v_oldavg || ' ' || v_newavg);
22
23 exception
24 when too_high then
25 dbms_output.put_line ('Specify less than 40 percent increase');
26 when no_data_found then
27 dbms_output.put_line ('You entered an invalid museum ID');
28 end;
29 /
Procedure created.
SQL> exec proc_second(1, 20);
You entered an invalid museum ID
PL/SQL procedure successfully completed.
SQL>
I have google the whole universe but cannot find out this.
Given data set A:
a b
1 2
3 4
1 2
I want to print this to result in this way:
a 1 3 1
b 2 4 2
Also print each variable, name first then content on one line to result.
I think you're looking for for proc transpose:
proc transpose data = A out = A_transpose;
var a b;
run;
Then you can print this with proc print:
proc print data = A_transpose;
run;
The following function definition does not give any errors, but neither does it work as intended. Can anyone help?
It is supposed to return one of the text abbreviations when supplied an int:
CREATE FUNCTION foo(a int)
RETURNS character
LANGUAGE SQL
AS $$
SELECT CASE C.INSURANCETYPE
WHEN 0 THEN 'MB' --MEDICARE
WHEN 1 THEN 'MC' --MEDICAID
WHEN 2 THEN 'OF' --OTHER FED
WHEN 3 THEN 'CH' --CHAMPVA
WHEN 4 THEN 'CI' --GROUP
WHEN 5 THEN 'OF' --OTHER FED
WHEN 6 THEN 'CI' --OTHER GROUP
END
FROM C
$$;
SELECT foo(0);
...returns nothing
Try this:
Declare #insuranceType as char
SET #insuranceType = (SELECT CASE C.INSURANCETYPE
WHEN 0 THEN 'MB' --MEDICARE
WHEN 1 THEN 'MC' --MEDICAID
WHEN 2 THEN 'OF' --OTHER FED
WHEN 3 THEN 'CH' --CHAMPVA
WHEN 4 THEN 'CI' --GROUP
WHEN 5 THEN 'OF' --OTHER FED
WHEN 6 THEN 'CI' --OTHER GROUP
END
FROM C)
RETURN #insuranceType
`CREATE or REPLACE FUNCTION NUM_TO_INSURANCE(NUM int) RETURNS varchar AS $body$
declare REL varchar;
begin
SELECT
CASE NUM --block_1
WHEN 0 THEN 'MB' --MEDICARE
WHEN 1 THEN 'MC' --MEDICAID
WHEN 2 THEN 'OF' --OTHER FED
WHEN 3 THEN 'CH' --CHAMPVA
WHEN 4 THEN 'CI' --GROUP
WHEN 5 THEN 'OF' --OTHER FED
WHEN 6 THEN 'CI' --OTHER GROUP
END
INTO REL;
RETURN REL;
END;
$body$ LANGUAGE plpgsql;`
I have the data in a sav file
CODE | QUANTITY
------|----------
A | 1
B | 4
C | 1
F | 3
B | 3
D | 12
D | 5
I need to obtain the quantity of codes which have a quantity <= 3 and to obtain the proportion in a percentage with respect to the total number and present a result like this
<= 3 | PERCENTAGE
------|----------
4 | 57 %
All of this using SPSS syntax.
I would first convert the quantity value to a 0-1 variable, and then aggregate by code to the mean. This produces a nice second dataset to make a table. Example below.
data list free / Code (A1) Quantity (F2.0).
begin data
A 1
B 4
C 1
F 3
B 3
D 12
D 5
end data.
*convert to 0-1.
compute QuantityB3 = (Quantity LE 3).
*Aggregate.
DATASET DECLARE AggQuant.
AGGREGATE
/OUTFILE='AggQuant'
/BREAK=Code
/QuantityB3 = MEAN(QuantityB3).
I dont know how you migrate your question here, I dont have reputation here to add screen shoots that's help you allot. Anyhow the procedure of your desire output is given below.
Goto Transform->Count Values within cases a dialogue box open, write the name of new variable say "New" in Target Variable: go to define values a new dialogue box is open then check the radio button Range, LOWEST through value: put in below box 3 and then press add and press continue and press ok. A new variable is created with the name of "New". Now go to Analyze -> Descriptive Statistics-> Frequencies, new dialogue box will be open send "New" variable into Variable(s): press Statistics in new dialogue box check Percentile(s): write 100 in box and press Add and then continue and ok. You get the desire results.