SQL Error: ORA-00933: SQL command not properly ended? - sql

I am wanting to insert data or to populate a table with new data and have used the insert into command on its own as well as insert into with the columns and values underneath but keep getting the error in the title.
INSERT INTO A2_FILM (FILM_NO, FILM_NAME, CLASSIFICATION, DURATION, DESCRIPTION, YEAR_RELEASED)
VALUES (00948371, 'Lightyear', 'U', 105, 'Legendary space ranger Buzz Lightyear embarks on an intergalactic adventure alongside ambitious recruits Izzy, Mo, Darby, and his robot companion, Sox.', TO DATE('2022', 'YYYY'));

With Oracle 19c and SqlDeveloper 21 i not received any error:
Name Null? Type
----------------------------------------------------- -------- ------------------------------------
FILM_NO NUMBER(12)
FILM_NAME VARCHAR2(100)
CLASSIFICATION CHAR(1)
DURATION NUMBER(5)
DESCRIPTION VARCHAR2(1000)
YEAR_RELEASED DATE
INSERT INTO A2_FILM (FILM_NO, FILM_NAME, CLASSIFICATION, DURATION, DESCRIPTION, YEAR_RELEASED)
VALUES (00948371,
'Lightyear',
'U',
105,
'Legendary space ranger Buzz Lightyear embarks on an intergalactic adventure alongside ambitious recruits Izzy, Mo, Darby, and his robot companion, Sox.',
TO_DATE('2022', 'YYYY')
);
1 row inserted.

If the populated value in YEAR_RELEASED column has to equal to YYYY, it looks like you have to change the datatype to NUMBER. Otherwise if you execute INSEERT INTO TO_DATE('2022', 'YYYY') will return DD-MM-YYYY which will be equal to SYSDATE, i.e. in this case the return value is 01-07-2022.
If you change the datatype to NUMBER for YEAR_RELEASED column you can use EXTRACT() and try this one:
INSERT INTO A2_FILM (FILM_NO, FILM_NAME, CLASSIFICATION, DURATION, DESCRIPTION, YEAR_RELEASED) VALUES (00948371, 'Lightyear', 'U', 105, 'Legendary space ranger Buzz Lightyear embarks on an intergalactic adventure alongside ambitious recruits Izzy, Mo, Darby, and his robot companion, Sox.', EXTRACT (YEAR FROM TO_DATE('2022-07-01', 'YYYY-MM-DD')));
db<>fiddle: https://dbfiddle.uk/?rdbms=oracle_18&fiddle=91ba7c0f3117bd6cfc814656a896856e
If the populated value has to be equal to DD-MM-YYYY you can use :
INSERT INTO A2_FILM (FILM_NO, FILM_NAME, CLASSIFICATION, DURATION, DESCRIPTION, YEAR_RELEASED) VALUES (00948371, 'Lightyear', 'U', 105, 'Legendary space ranger Buzz Lightyear embarks on an intergalactic adventure alongside ambitious recruits Izzy, Mo, Darby, and his robot companion, Sox.', TO_DATE('2022', 'YYYY'));
db<>fiddle: https://dbfiddle.uk/?rdbms=oracle_18&fiddle=41aac71840efc45eaa62e9db42fb75c5

Related

Filter condition using "parent" CurrentMember

Here is the data-set:
CREATE TABLE Movies(id INT, name VARCHAR(50), genre VARCHAR(50), budget DECIMAL(10));
INSERT INTO Movies VALUES
(1, 'Pirates of the Caribbean', 'Fantasy', 379000000),
(2, 'Avengers', 'Superhero', 365000000),
(3, 'Star Wars', 'Science fiction', 275000000),
(4, 'John Carter', 'Science fiction', 264000000),
(5, 'Spider-Man', 'Superhero', 258000000),
(6, 'Harry Potter', 'Fantasy', 250000000),
(7, 'Avatar', 'Science fiction', 237000000);
To filter relatively to a constant value no problem, e.g. to get all the movies with a budget higher than 300M$:
WITH
MEMBER X AS SetToStr(Filter(Movie.[Name].[Name].Members - Movie.[Name].CurrentMember, Measures.Budget > 300000000))
SELECT
Movie.[Name].[Name].Members ON ROWS,
X ON COLUMNS
FROM
Cinema
Which gives:
Avatar {[Movie].[Name].&[Avengers],[Movie].[Name].&[Pirates of the Caribbean]}
Avengers {[Movie].[Name].&[Pirates of the Caribbean]}
Harry Potter {[Movie].[Name].&[Avengers],[Movie].[Name].&[Pirates of the Caribbean]}
John Carter {[Movie].[Name].&[Avengers],[Movie].[Name].&[Pirates of the Caribbean]}
Pirates of the Caribbean {[Movie].[Name].&[Avengers]}
Spider-Man {[Movie].[Name].&[Avengers],[Movie].[Name].&[Pirates of the Caribbean]}
Star Wars {[Movie].[Name].&[Avengers],[Movie].[Name].&[Pirates of the Caribbean]}
But how to compare to the budget of the current movie instead of the hard-coded 300M$ to get the movies more expensive than the current one?
It would give {} for "Pirates of the Caribbean" as it is the most expensive movie.
For "Avengers" it would be { 'Pirates of the Caribbean' } as this is the second most expensive and only "Pirates of the Caribbean" is more expensive.
For "Avatar" it would give all the other movies as it is the less expensive.
The issue is that inside the Filter function's condition CurrentMember refers to the currently tested tuple and not the one currently selected on the ROWS axis.
Instead of using Filter() for each movie, I would first compute an ordered set of movies based on budget values. Then X could be defined using the SubSet and Rank function.
Here is an example using a different schema but I guess you'll get the point easily:
with
set ordered_continents as order( [Geography].[Geography].[Continent], -[Measures].[#Sales] )
member xx as SetToStr( SubSet( ordered_continents, 0, Rank( [Geography].[Geography].currentMember, ordered_continents) - 1))
select {[#Sales], [xx] } on 0, [Geography].[Geography].[Continent] on 1 from [Sales]
I'm not familiar with SSAS so I'm using icCube but I guess the MDX should be very much similar.

SQL Query: finding cheapest car by company

Following YouTube tutorial "Learn PostgreSQL Tutorial - Full Course for Beginners", I replicate teacher's code but yields different result and cannot figure out why.
Table is this simple:
id | make | model | price
-----+------------+--------------+------------
1 | Toyota | Matrix | 25451.36
and so on, 1000 entries.
Querying cheapest model from manufacturer, tutorial says:
SELECT
make, model, MIN(price)
FROM
car
GROUP BY
make, model;
And it works properly, returning as many entries as distinct car makers.
But when I run it in my PostgreSQL terminal returns all 1000 entries disordered.
However, when I query without model's name, I get the right answer, but (obviously)
without the model name as shown below:
make | cheapest
---------------+----------
Fillmore | 72263.48
McLaren | 78510.84
Any suggestions as to why this might happen?
This db-fiddle works as expected. Notice the output. It shows a proper GROUP BY.
Query source:
CREATE TABLE t (
make varchar(40),
model varchar(40),
price integer
);
INSERT INTO t (make, model, price) VALUES
('Fillmore', 'F_M1', 10000),
('Fillmore', 'F_M2', 20000),
('McLaren', 'M_M2', 40000),
('McLaren', 'M_M2', 60000),
('Toyota', 'T_M1', 12000),
('Toyota', 'T_M2', 24000),
('Toyota', 'T_M3', 48000);
SELECT
make, model, MIN(price)
FROM
t
GROUP BY
make, model
ORDER BY make, model;
Result:
Schema (PostgreSQL v10.0)
CREATE TABLE t (
make varchar(40),
model varchar(40),
price integer
);
INSERT INTO t (make, model, price) VALUES
('Fillmore', 'F_M1', 10000),
('Fillmore', 'F_M2', 20000),
('McLaren', 'M_M2', 40000),
('McLaren', 'M_M2', 60000),
('Toyota', 'T_M1', 12000),
('Toyota', 'T_M2', 24000),
('Toyota', 'T_M3', 48000);
Query #1
SELECT
make, model, MIN(price)
FROM
t
GROUP BY
make, model
ORDER BY make, model;
make
model
min
Fillmore
F_M1
10000
Fillmore
F_M2
20000
McLaren
M_M2
40000
Toyota
T_M1
12000
Toyota
T_M2
24000
Toyota
T_M3
48000
View on DB Fiddle

SQL - count function not working correctly

I'm trying to count the blood type for each blood bank I'm using oracle DB
the blood bank table is created like this
CREATE TABLE BloodBank (
BB_ID number(15),
BB_name varchar2(255) not NULL,
B_type varchar2(255),CONSTRAINT
blood_ty_pk FOREIGN KEY
(B_type) references BloodType(B_type),
salary number(15) not Null,
PRIMARY KEY (BB_ID)
);
INSERT INTO BloodBank (BB_ID,BB_name,b_type, salary)
VALUES (370,'new york Blood Bank','A+,A-,B+',12000);
INSERT INTO BloodBank (BB_ID,BB_name,b_type, salary)
VALUES (791,'chicago Blood Bank','B+,AB-,O-',90000);
INSERT INTO BloodBank (BB_ID,BB_name,b_type, salary)
VALUES (246,'los angeles Blood Bank','O+,A-,AB+',4500);
INSERT INTO BloodBank (BB_ID,BB_name,b_type, salary)
VALUES (360,'boston Blood Bank','A+,AB+',13000);
INSERT INTO BloodBank (BB_ID,BB_name,b_type, salary)
VALUES (510,'seattle Blood Bank','AB+,AB-,B+',2300);
select * from BloodBank;
when I use the count function
select count(B_type)
from bloodbank
group by BB_ID;
the result would be like this
so why the count function is not working correctly?
I'm trying to display each blood bank blood type count which is not only one in this case
I hope I don't get downvoted for solving the specific problem you're asking about, but this query would work:
select bb_id,
bb_name,
REGEXP_COUNT(b_type, ',')+1
from bloodbank;
However, this solution ignores a MAJOR issue with your data, which is that you do not normalize it as #Tim Biegeleisen correctly instructs you to do. The solution I've provided is EXTREMELY hacky in that it counts the commas in your string to determine the number of blood types. This is not at all reliable, and you should 100% do what Tim B recommends. But for the circumstances you find yourself in, this will tell you how many different blood types are kept at a specific blood bank.
http://sqlfiddle.com/#!4/8ed1c2/2
You should normalize your data and get each blood type value onto a separate record. That is, your starting data should look like this:
BB_ID | BB_name | b_type | salary
370 | new york Blood Bank | A+ | 12000
370 | new york Blood Bank | A- | 12000
370 | new york Blood Bank | A+ | 12000
... and so on
With this data model, the query you want is something along these lines:
SELECT BB_ID, BB_name, b_type, COUNT(*) AS cnt
FROM bloodbank
GROUP BY BB_ID, BB_name, b_type;
Or, if you want just counts of types across all bloodbanks, then use:
SELECT b_type, COUNT(*) AS cnt
FROM bloodbank
GROUP BY b_type;

Find string match to Oracle table using regex

I have an Oracle stored procedure on an Oracle 12c database that receives a company_name input. From that company_name, I need to find and flag Federal institutions. To accomplish that, I have a table (TBL_FED_KEY) with one column (KEY_1) of keywords. The table contains nearly 50 values like:
ARMY
FEDERAL
AIR FORCE
VETERANS
HOMELAND SECURITY
INDIAN HOSPITAL
WILL ROGERS
To give you an idea of the company_name string that could be passed through to the procedure, here are examples:
US Army - Munson Health Center
Federal Bureau of Prisons,BOP/DOJ-
Hickam Air Force Base Pharmacy
Minnesota Veterans Home Pharmacy
P.H.S. Indian Hospital
Will Rogers Health Center
What Oracle SQL can be used to match the incoming company_name against TBL_FED_KEY.KEY_1? I've tried multiple variations of REGEXP_INSTR but I can't seem to get anything to work 100%. Is REGEXP_INSTR even the best tool to accomplish this?
Thanks!
You could just use like:
select f.*
from TBL_FED_KEY f
where lower(i.name) like '%' || lower(KEY_1) || '%'
Seems you want case-insensitive match among those string. So, use REGEXP_LIKE() function with case-insensitive(i) option :
SELECT *
FROM TBL_FED_KEY
WHERE REGEXP_LIKE(company_name,key_1,'i')
I am not sure what the procedure is supposed to do after it "flags" the company as federal vs. not. I would instead write it as a function as shown below (but you can easily reuse most of the code in a procedure, if needed).
Then I illustrate how the function can be used directly in SQL. You can also use it in PL/SQL if needed, but in most cases you don't. Note - the same idea can be implemented exclusively in SQL, resulting in faster execution, since you don't need PL/SQL at all. Important - even in plain SQL, this should be implemented via a semi join, as I demonstrated, for faster execution.
Setup:
create table tbl_fed_key (key_1 varchar2(200));
insert into tbl_fed_key
select 'ARMY' from dual union all
select 'FEDERAL' from dual union all
select 'AIR FORCE' from dual union all
select 'VETERANS' from dual union all
select 'HOMELAND SECURITY' from dual union all
select 'INDIAN HOSPITAL' from dual union all
select 'WILL ROGERS' from dual
;
commit;
Function code:
create or replace function is_federal_institution(company_name varchar2)
return varchar
deterministic
as
is_fed varchar2(1);
begin
select case when exists ( select key_1
from tbl_fed_key
where instr(upper(company_name), upper(key_1)) > 0
)
then 'Y' else 'N' end
into is_fed
from dual;
return is_fed;
end;
/
SQL test:
with
inputs (str) as (
select 'Joe and Bob Army Supply Store' from dual union all
select 'Mary Poppins Indian Hospital' from dual union all
select 'Bridge Association of NYC' from dual union all
select 'Will Rogers Garden' from dual union all
select 'First Federal Bank NA' from dual
)
select str, is_federal_institution(str) as is_federal
from inputs
;
STR IS_FEDERAL
------------------------------ ----------
Joe and Bob Army Supply Store Y
Mary Poppins Indian Hospital Y
Bridge Association of NYC N
Will Rogers Garden Y
First Federal Bank NA Y
As you can see, I threw in a few false positives - to illustrate the important fact that this "technological" solution is only partial. A human will still need to review the individual hits, if accuracy is important.

SQL Masking A Mapping Field In The Query

I am creating a view to extract data from a table and load that data into a fixed file which will be loaded into a system. The view will map the table column to a particular format.
There is one column, Account_Number, which needs to be masked as the column has sensitive information.
My logic to mask the value is to shift the number to the next place in numberline.
so, if the number is 0 then 1, 4 then 5, etc. I am not able to come with the logic in the view itself.
Any help would be appreciated.
CREATE OR REPLACE FORCE EDITIONABLE VIEW "Schema1"."VW_ActiveTraders" ("FUND", "NAME", "CITY", "ACN") AS
Select
TD_Fund as FUND,
Name as NAME,
City as CITY,
Account_Number as ACN
FROM Trader1 -- Table Name
Account Number
023457456
123456789
012345678
Masked Account Number
134568567
012345678
123456789
Please note that Account Number column has more than 1000 entries.
You may use TRANSLATE to shift the numbers
with dt as (
select '023457456' ACN from dual union all
select '123456789' ACN from dual union all
select '012345678' ACN from dual)
select ACN,
TRANSLATE(ACN,'0123456789','1234567890') as ACN_WEAK_MASK
from dt;
ACN ACN_WEAK_
--------- ---------
023457456 134568567
123456789 234567890
012345678 123456789
But note, that this is not a real masking of sensitive information. It is very easy to unmask the information and get the original acount ID.
An often used masking is e.g. 012345678 gets ******678.
#MarmiteBomber #Stilgar - Thanks so much for clarification and help on the answer.
I just tweaked the query and it ran successfully.
Changed Query
------------------------------------------------------------------------------------------
CREATE OR REPLACE FORCE EDITIONABLE VIEW "Schema1"."VW_ActiveTraders" ("FUND", "NAME", "CITY", "ACN") AS
Select
TD_Fund as FUND,
Name as NAME,
City as CITY,
--Account_Number as ACN
TRANSLATE(Account_Number,'0123456789','1234567890') as ACN,
FROM Trader1 -- Table Name
------------------------------------------------------------------------------------------