Prevention triggers - sql

I have a table like this:
StudentID Student Name Birthdate Student Birthplace Gender Height Weight
--------- --------------- --------- ------------------ ------ ------ ------
83 Adam Stone 30-JUN-94 Towson, USA M 193 88
84 Stephanie Love 17-JUN-93 KL,Malaysia F 176 67
85 Rachel Kim 17-FEB-92 Seoul, South Korea F 179 56
How do i write a trigger to prevent any student under the age of 15 from being stored in the student's table?

You have a Date of Birth. So you need to determine that the DoB is at least sixteen years before today. There are various different ways of doing this; here's one using an interval literal.
create or replace trigger students_biur
before insert or update on students for each row
begin
if (:new.student_birthdate + INTERVAL '15' YEAR ) < sysdate
then
raise_application_error( -20000, 'This student is too young be registered.');
end if;
end;
This trigger also checks for updates, to prevent subsequent changes invalidating an student.
The trigger name students_biur is just a convention I use: the table name with a suffix indicating *B*efore *I*nsert *U*pdate for each *R*ow.
RAISE_APPLICATION_ERROR is a standard procedure for throwing user-defined exceptions with a message. Find out more.
Oracle reserves the range -20999 to -20000 for user-defined errors; any other number may clash with a oracle-defined exception.

Related

How can I add data from table to other in SQL?

I have 2 departments and created a new one, I want to update employee department but if that employees id equals one of id's listed in other table.
Employees
empid empname deptname
------------------------
01 john dept1
02 bill dept2
03 alex dept1
.
.
.
80 tomas dept1
New_depts_employees_id
empid
-----
02
05
45
18
20
34
78
80
55
32
If employee's id is inside the second table his depname will become 'dept3'
How can I write code make this process in SQL language (I using MS Access).
Do you want sql? You can use update and exists as follows:
Update employees
Set dept_name = 'dept3'
Where exists (select 1 from New_depts_employees_id n where n.emp_id = employees.emp_id)
Open new query constructor.
Add both tables to it.
Drag Employees.empid and drop it onto New_depts_employees_id.empid - a link occures. Not needed if the link is created automatically.
Change query type to UPDATE.
Set "Column to update" to Employees.deptname.
Set "Value to set" to 'dept3'.
Click "Execute".
You may save this query and convert static 'dept3' value to query parameter for future use from external application. Or you may open query constructor in SQL Mode and copy query text from it for external use.

Query with input parameter won't compile as a view

So I am trying to create a view that allows the user (from the front-end) query on it by specifying a specific date (in the form of a varchar/string). The view/query will then return data for the month of the specified date and also data for 13 months prior to it. When I run the following query and enter a valid 'string'/date , I am able to return results successfully. However, when I try to create a view with the same query, i am receiving the following error:
SQL Error: ORA-01027: bind variables not allowed for data definition operations
Below is the query:
SELECT person_name
, person_age
, person_dob
FROM person p
WHERE p.person_dob >= add_months(to_date(:par_date, 'yyyy-mm-dd'), -13);
Here is some sample data:
Person_Name Person_Age Person_DOB
Jon 18 01-01-1990
Jacob 21 09-04-1994
Heidi 28 04-02-2010
mark 30 05-02-2011
Helga 18 03-02-2015
Mike 18 01-02-1992
Larry 18 01-04-1993
I want to return the following result after specify :par_date as '2020-03-02'.
Person_Name Person_Age Person_DOB
Heidi 28 04-02-2010
mark 30 05-02-2011
Helga 18 03-02-2015
You unfortunately cannot do this. The closest you could come would be to create a table function, but that will be much less efficient than just selecting from the table with a 'WHERE' clause.
Ask Tom has a work around, but it is complex, much more work, and potentially very inneficient. Just use a 'WHERE' clause on the view or table
https://asktom.oracle.com/pls/apex/f?p=100:11:0::::P11_QUESTION_ID:9536277800346269502

how to retrieve a record always first and rest of the records using orderby?

I am new to Laravel.
I am trying to retrieve some records from a database. I need one of the row to be always in the first place, and rest in alphabetical order.Like this :
CategoryID Category
---------------------------
54 New Products
1 Amino Acids
3 b---
34 c----
4 d---
How should I rewrite my code to achieve this?
$db_categories = Category::get();
Thanks in advance.
You can use this:
Category::orderBy(DB::raw("IF(category = 'New Products', 0, 1), Category"))->get();
I don't know Laravel, but - as you tagged the question with SQL-ish tags, here you go: use CASE (or similar function, available in the database you use; such as DECODE in Oracle). For example:
I want to have DEPTNO = 30 (department number) first
the rest should be sorted by DNAME (department name), alphabetically
SQL> select * from dept
2 order by case when deptno = 30 then 1
3 else 2
4 end,
5 dname;
DEPTNO DNAME LOC
---------- -------------- -------------
30 SALES CHICAGO
10 ACCOUNTING NEW YORK
40 OPERATIONS BOSTON
20 RESEARCH DALLAS
SQL>
Hopefully, you'll be able to use something like that in your case.

How to create a table in Oracle 11g with the list of language codes based on util_i18n?

The other day I asked how to generate a list of currencies based on a built-in oracle table if possible: Does oracle provide a built-in currency table for me to use as constraints?.
Now I need a list of the language codes, so I went to read the documentation for util_i18n and I found a function named GET_LOCAL_LANGUAGES. I tried to adapt the script from the previous answer to this new problem but failed. This is mainly because my oracle/sql knowlegde is terrible:
The original I'm trying to adapt from:
select utl_i18n.GET_DEFAULT_ISO_CURRENCY(value) iso_cur
from v$nls_valid_values
where parameter = 'TERRITORY'
My attempt to use it for the languages:
select utl_i18n.GET_LOCAL_LANGUAGES(value) lang_cur
from v$nls_valid_values
where parameter = 'TERRITORY'
I checked the docs and TERRITORY is the parameter name as well, that part was not a guess. With this query I get error: invalid data type
I bet this is a noob question, but all my tries have failed so far.
You can use pipelined wrapper for example (original function returns package-defined collection type):
SQL> create type t_lang_tab is table of varchar2(4000)
2 /
SQL> create or replace function get_language(
2 p_value in varchar2
3 ) return t_lang_tab
4 pipelined
5 is
6 res utl_i18n.string_array;
7 begin
8 res := utl_i18n.GET_LOCAL_LANGUAGES(p_value);
9 if res is not null then
10 for i in 1..res.count loop
11 pipe row (substr(res(i),1,4000));
12 end loop;
13 end if;
14 return;
15 end;
16 /
SQL> col column_value format a25
SQL> col value format a25
SQL> select t.column_value, p.value
2 from v$nls_valid_values p,
3 table(get_language(p.value)) t
4 where parameter = 'TERRITORY'
5 /
COLUMN_VALUE VALUE
------------------------- -------------------------
ENGLISH AMERICA
GERMAN DIN GERMANY
CANADIAN FRENCH CANADA
FRENCH CANADA
CATALAN SPAIN
SWEDISH FINLAND
PORTUGUESE BRAZIL
LATIN AMERICAN SPANISH MEXICO
SPANISH MEXICO
SPANISH CATALONIA
ARABIC EGYPT
....
If you want to create language table you can do this:
SQL> CREATE TABLE languages (
2 country VARCHAR2(30) NOT NULL,
3 language VARCHAR2(30) NOT NULL,
4 CONSTRAINT languages_pk PRIMARY KEY (country, language)
5 )
6 /
Primary key should be composite because there are multi-lingual countries like Canada.
Now you can use above function to fill table:
SQL> INSERT INTO languages
2 select p.value, t.column_value
3 from v$nls_valid_values p,
4 table(get_language(p.value)) t
5 where parameter = 'TERRITORY'
6 order by 1
7 /
SQL> commit;
SQL> select * from languages;
COUNTRY LANGUAGE
------------------------------ ------------------------------
AMERICA ENGLISH
ARGENTINA SPANISH
BELARUS RUSSIAN
BELGIUM FRENCH
BRAZIL PORTUGUESE
CANADA FRENCH
CANADA CANADIAN FRENCH
CATALONIA SPANISH
CHILE SPANISH
COLOMBIA SPANISH
...

SQL Nested Query based on value of Dependent Column

In the below table structure, TB_Vehicles is the Master table and TB_Cars, TB_Bikes, TB_Cars are Satellite tables which hold more info about respective vehicles.
**TB_Scooters**
V_NAME V_ID V_YEAR V_TYPE V_MILEAGE
Activa 10 2003 Scooter 45
Access 20 2004 Scooter 50
**TB_Bikes**
V_NAME V_ID V_YEAR V_TYPE V_ENGINE
Karizma 30 2001 Bike 180
Pulsar 40 2008 Bike 150
**TB_Cars**
V_NAME V_ID V_YEAR V_TYPE V_CAR_TYPE
Linea 50 2011 Car Sedan
i20 60 2012 Car Sedan
**TB_Vehicles**
V_NAME V_ID V_YEAR V_TYPE V_COLOR V_AVAILABLE
Activa 10 2003 Scooter Black Yes
Access 20 2004 Scooter Black No
Karizma 30 2001 Bike Red Yes
Pulsar 40 2008 Bike Black Yes
Linea 50 2011 Car White No
i20 60 2012 Car Red Yes
I want users to search using the Name. So, when users enter Name as 'Access', my query should give all information about that vehicle, including that from Satellite Tables (using both TB_Vehicles and TB_Scooters).
SELECT * FROM TB_Vehicles
WHERE V_NAME = 'Access';
Similarly, if user enters 'Linea', it should give info from TB_Vehicles and TB_Cars tables.
So, with V_NAME as input, I'll find V_TYPE from TB_Vehicles table, and using that, I need to identify which satellite table, I need to join to retrieve more info.
How do I do this? Can you please help me with the query? Do I need to use CASE or DECODE to achieve this?
EDIT:
The requirement here is to display only those columns which are applicable for that particular vehicle type. So, when user gives 'Access' as input, it should display all columns from TB_Vehicles table, and V_MILEAGE from TB_Scooters table.
I was thinking whether this can be done using CASE or DECODE, where I first identify the type (V_TYPE) of the vehicle from TB_Vehicles table using the input name (V_NAME), and then based on this V_TYPE, I'll search the relevant table and display only relevant columns.
When Input Name is 'Access', then result should be:
V_NAME V_ID V_YEAR V_TYPE V_COLOR V_AVAILABLE V_MILEAGE
Access 20 2004 Scooter Black No 50
When Input Name is 'i20', then result should be:
V_NAME V_ID V_YEAR V_TYPE V_COLOR V_AVAILABLE V_CAR_TYPE
i20 60 2012 Car Red Yes Sedan
You shouldn't be storing the name in both the vehicles tables and the subtables. If this is common information, then just store it in the vehicles table. This is true of all the common columns.
Next, when you access data, do it by bringing together all the tables:
select v.*,
s.v_mileage, b.v_engine, c.v_car_type
from TB_vehicles v left join
TB_Scooters s
on s.v_id = v.v_id and v.type = 'scooter' left join
TB_Bikes b
on b.v_id = v.v_id and v.type = 'bike' left join
TB_Cars c
on c.v_id = v.vid and v.type = 'car';
From this query, you can then choose the row and the fields that you want.
However, you need to work on normalizing your data structure so fields like v_year are only in one table.
Thanks Gordon! Appreciate your help over this...
For others with similar query, please look into the above response from Gordon as well as the below link:
http://www.orafaq.com/forum/t/189451/180198/