SQL> set serverout on
SQL> CREATE PROCEDURE find employees
2 BEGIN
3 if Department_ID < 50 from Employees
4 THEN
5 RETURN select Employee_ID, First_Name, Last_Name, Department_ID from Employees where Department_ID < 50;
6 ELSE
7 RETURN select Employee_ID, First_Name, Last_Name, Department_ID from Employees where Department_ID > 50;
8 END IF;
9 /
Warning: Procedure created with compilation errors.
Nothing about this makes sense.
Return can only return integers and is used only for returning error codes.
This is an incorrect use of If as well in two different ways. Where are you getting the value of Department_id? And look up the syntax for If as you are way off.
Of course you wouldn't have line numbers in the actual stored proc.
It is a poor practice to name a proc with spaces, do not do that.
A number of issues I can see (assuming per the tag that this is MS-SQL):
find employees isn't a valid proc name, due to the space. To absolutely force it to accept the space (warning: bad idea!!) you could surround it in brackets like [find employees] but I would definitely recommend something like find_employees instead.
You are missing an END to signify the end of your proc.
You don't use RETURN inside a stored proc, only inside a function. Are you trying to pass a result set to whatever called it (in which case you'd need a "table-valued function")? Or just display the results?
Are you trying to pass in Department_ID? In other words, to give it a different Department_ID each time you run? In that case you'll need a #Department_ID parameter or something. Or is it getting it from a table?
I can't fathom your business logic, it makes no sense. Why are you returning two different lists of employees? Are you trying to count how many employees belong to each dept? Is this some kind of "paging" logic (retrieving only 50 employees at a time)?
Your IF syntax is way off. should be something like IF #Department_ID < 50 (for a parameter) or maybe IF (SELECT COUNT(*) FROM Employees WHERE Department_ID = #Department_ID) > 50 or something, but again, I'm having a hard time trying to figure out what you're trying to do.
SQL doesn't use END IF. Look up the syntax for single-line IF ELSE statements and multi-line IF ELSE statements.
Warning: Procedure created with compilation errors.
Yep.
there is no END to the CREATE statement...
There is no definition of department_id...
there are no parameters declared for the IF statement to work on...
The function name has a space in it...
Related
I have some useful queries, I'd like to build a few more complex ones that needs them as sub queries. Can I call them by name ?
I'v seen the 'save view' option and was able to build new queries that used saved views.
Does this method refreshes the saved view each time a top query uses it, by re-executing the relevant queries ? or is it just a named query result, that I have to rerun each time to refresh ?
other suggestions to build queries in modular fashion ? For example when I change the days range I select from I want all subqueries to use the range.
In programming it's either using promoters or globals, how to do this in BigQuery ?
Whilst it is very diffcult to address your questions due to its broadness. I will answer them with general guidelines and examples for each doubt.
Regarding your first question, about subqueries and calling queries by an alias. I have 2 considerations about these:
1) You can use subqueries with WITH. So, you perform your transformations in the data, save it in a temporary table and reference it in the following (sub)query. Moreover, every time you run the code, all the queries will be executed. Below is an example,
WITH data as (
SELECT "Alice" AS name, 39 AS age, "San Francisco" AS city UNION ALL
SELECT "Marry" AS name, 35 AS age, "San Francisco" AS city UNION ALL
SELECT "Phill" AS name, 18 AS age, "Boston" AS city UNION ALL
SELECT "Robert" AS name, 10 AS age, "Tampa" AS city
),
greater_30 AS (
SELECT * FROM data
WHERE age > 30
),
SF_30 AS (
SELECT * FROM greater_30
WHERE city = "San Francisco"
)
SELECT * FROM SF_30
and the output,
Row name age city
1 Alice 39 San Francisco
2 Marry 35 San Francisco
2) Create a Stored Procedure: procedures are blocks of statements which can be called from other queries and also executed recursively ( call one procedure inside other). In order to create and store a procedure you have to specify the project and dataset where it will be saved. As well as, its name. Below is an example (using a BigQuery public dataset),
#creating the procedure
CREATE or replace PROCEDURE project_id.ataset.chicago_taxi(IN trip_sec INT64, IN price INT64)
BEGIN
CREATE TEMP TABLE taxi_rides AS
SELECT * FROM `bigquery-public-data.chicago_taxi_trips.taxi_trips`
WHERE trip_seconds > trip_sec and fare >price
LIMIT 10000
;
END;
Now, you can call the procedure using CALL. As follows:
DECLARE trip_sec INT64 DEFAULT 30;
DECLARE price INT64 DEFAULT 30;
CALL `project_id.ataset.chicago_taxi`(trip_sec, price);
SELECT max(fare) AS max_fare,payment_type FROM taxi_rides
GROUP BY payment_type
And the output,
Row max_fare payment_type
1 463.45 Cash
2 200.65 Credit Card
Notice that the procedure is saved within the dataset. Then we use CALL to call it and use its output (a temporary table) in the next select statement. I must point that every time the procedure is invoked, it executes the query.
Regarding your question about saved views: the view is updated every time you run it. Please refer to the documentation.
Finally, about the last question using parameters and globals in queries: you can use scripting in BigQuery in order to DECLARE and SET a variable. So, you can take advantages when changing filter parameters for example. Below there is an usage example using a public a public dataset,
DECLARE time_s timestamp;
SET time_s= timestamp(DATETIME "2016-01-01 15:30:00");
SELECT * FROM `bigquery-public-data.chicago_taxi_trips.taxi_trips`
WHERE trip_start_timestamp > time_s
LIMIT 10000
Pay attention that every time the filter needs to be changed, it is possible to do it from the SET statement.
Note: If you have any specific question, please open another thread or you can ask me in the comment section.
I'm working with Oracle but I would be interested in whether this is possible in any sql flavor. Essentially I have a long select statement; I need to confirm that the select returns a certain number of records (the output of a separate select count(*)) and I haven't been able to figure out how to do this programmatically (or solve the problem that prevents me from knowing that my query is 100% correct from the get-go).
Ideally, I want to add a few lines so that, either the correct set is returned, or an error is thrown
So this is done on MS-SQL but I'm sure you could easily make it work for Oracle if you felt inclined:
DECLARE #err_message nvarchar(255)
set #err_message = 'Doesnt match count expected'
IF
(select count(*) [Counter] from(
select ordernum from erp.orderhed where ordernum > 390000) as Ordercount) <> 3412
raiserror(#err_message,11,1)
ELSE
select ordernum from erp.orderhed where ordernum > 390000
In this example I know (because I checked) that there is exactly 3412 rows that will be returned from that query, so it'll go into the ELSE and return my query (which could be stored as a view for readability). If that count changes then it will raise the exception with the message I wrote.
I'm not sure how you mean to use it but I'd imagine this would fit into a stored procedure fairly well.
I'm trying to implement a stored function in PL/SQL that finds the total number of cities visited by a given driver, return the driving license number.
I tried something like this, but i keep getting "Function created with compilation errors.". The thing is, oracle 11g doesn't show where is the error at?
Here is what i got.
create or replace function driverL return number
as licence L#%TYPE;
begin
select L#, count(T#)
from driver d
join trip t ON d.L# = t.L#
join leg l ON l.t# = l.t#;
return licence;
end;
/
How do i consider multiple visits to the same city as one visit?
If you are using SQL*Plus you can use the statement show errors after the create statement to show the compilation errors for the most recently created or altered stored procedure/function/package.
In your code I see at least two problems:
You are missing an INTO clause in your select
The column L# in your SELECT clause is ambiguously defined since two tables have a column with that name
I have some code that runs the same query in 2 different databases.
SELECT
P.MYID,
CASE WHEN
SUBSTR(P.MYID, 1, 1) NOT IN ('W') THEN
'YOUR_ID_IS_NOT_START_WITH_W'
ELSE
(SELECT OTHER_ID FROM PERSON WHERE NUMBER = '2554' )
END AS "ALTERNATE_ID"
FROM
PERS_INFO P
WHERE
P.NUMBER = '2554'
OTHER_ID in this example is a column that only exists in the 2nd database. Thats completely fine because the query will only execute in the 1st database when the id DOES NOT start with 'W'. In otherwords, this query will only ever run in the 1st database, when the MYID does not start with 'W' and will only ever run in the 2nd database when MYID does start with 'W'.
So the query would work in both databases, however, the query fails with an ORA-00904 in the first database because it says OTHER_ID is not legal in the first database (which is true, but i dont care). how do i force oracle to run the query anyways or work around this?
You could create a function in both databases to get the OTHER_ID value. It would just return null in your first database.
For example, in the first database:
create or replace function f_get_other_id(for_no in varchar2) return varchar2 is
begin
return null;
end;
In the second database:
create or replace function f_get_other_id(for_no in varchar2) return varchar2 is
v_other_id varchar2(100);
begin
select other_id into v_other_id from person where number = for_no;
return other_id;
end;
Then, your query can be:
select p.myid,
case
when substr(p.myid, 1, 1) not in ('W') then 'YOUR_ID_IS_NOT_START_WITH_W'
else f_get_other_id('2554')
end as "ALTERNATE_ID"
from pers_info p
where p.number = '2554'
Have you heard about the EXECUTE_IMMEDIATE (http://docs.oracle.com/cd/B19306_01/appdev.102/b14261/executeimmediate_statement.htm) command or about DBMS_SQL (see http://docs.oracle.com/cd/B28359_01/appdev.111/b28419/d_sql.htm)?
If you are working with scripts on various databases that have different tables definition, this might be the solution for you, though this requires PL/SQL.
I'm not sure what the problem would be with adding this column to the database that it is currently absent from, but adding it seems like a pretty low effort and low risk exercise, and would permanently solve this kind of problem.
Probably you need to add another CASE after else checking the database name. Case db_name = db_name1 then your other_id query else some other query lk select 1 from dual... You can get db_name from v$database view.
Hey guys i cant get this trigger to work, ive worked on it for an hour or so and cant see to figure out where im going wrong, any help would be appreciated
CREATE OR REPLACE TRIGGER allergy
BEFORE INSERT ON
DECLARE
med VARCHAR2(20);
BEGIN
SELECT v.medication RCD.specify
INTO med
FROM visit v, relcondetails RCD
WHERE :new.medication = v.medication AND RCD.specifiy = 'allergies';
IF med = allergies THEN
RAISE_APPLICATION_ERROR(-20000, 'Patient Is alergic to this medication');
END IF;
END allergy;
When put into oracle
ERROR at line 6: ORA-04079: invalid
trigger specification
CREATE OR REPLACE TRIGGER allergy BEFORE INSERT ON
name of table here
FOR EACH ROW -- forgot this too
DECLARE
med VARCHAR2(20);
You should really be declaring this as %type.
med visit.medication%type;
BEGIN
SELECT v.medication RCD.specify
Requires a comma between columns
INTO med
Two columns need two variables
FROM visit v, relcondetails RCD
WHERE :new.medication = v.medication AND RCD.specifiy = 'allergies';
You have no join condition between your two tables, that's very bad. This query will perform a Cartesian between the two tables and then return all of them that have 'allergies' and :new.medication in their respective columns.
you also probably need a filter condition to limit the query to a particular patient or a particular visit. This query will do it for all patients and all their visits squared.
IF med = allergies THEN
I don't know what /allergies/ is in this IF. There's no variable that's defined as that and without quotes it's not a string.
RAISE_APPLICATION_ERROR(-20000, 'Patient Is alergic to this medication');
This error message reinforces what I said about your query. You think you're querying for a single patient but you're not.
END IF;
END allergy;
Seriously, if you're writing software to save a person from getting potentially life threatening medication then please consider some other line of work. I swear I'm not saying this to be rude, but your code sample shows almost no understanding of the pl/sql language or sql or any scrap of programming background. I think you started with some sample code and tried to modify it into something something. But you're really left with gibberish. I'm starting to think this is homework.
In addition to Mark's point that you are missing the table name, and Martin's point that you want this to be a row-level trigger, your actual body won't compile, for a couple of reasons.
You look like you're trying to select two columns, but you don't have a comma between them, and you only have one local variable in the INTO clause
You use an identifier allergies which is not declared anywhere.
I also doubt that your query is logically correct, but of course I don't know the database design so I can't say for sure.
BEFORE INSERT ON <TABLE NAME>
and why select both v.medication and RCD.specify when you're only selecting into one variable?
You've probably seen this but:
http://msdn.microsoft.com/en-us/library/aa258254(SQL.80).aspx
CREATE TRIGGER TriggerName
ON MyTableName
FOR MyEvent
AS
-- My Trigger Logic