Missing expression inside sub-query statement? - sql

I am using the infamous "CityJail" schema to answer a question "List the names of all criminals who have committed more than average number of crimes and aren’t listed as violent offenders."
Here is my code:
SELECT first, last
FROM criminals NATURAL JOIN
crimes
GROUP BY first, last
HAVING COUNT(*) > (SELECT AVG(COUNT(DISTINCT crime_id))
FROM crimes)
AND (SELECT v_status = 'N' FROM crimes)
GROUP BY first, last
);
but I get an error:
ORA-00936: missing expression
00936. 00000 - "missing expression"
*Cause:
*Action:
Error at Line: 7 Column: 22
When I change my code to:
SELECT first, last
FROM criminals NATURAL JOIN
crimes
GROUP BY first, last
HAVING COUNT(*) > (SELECT AVG(COUNT(DISTINCT crime_id))
FROM crimes)
AND v_status = 'N'
GROUP BY first, last
);
I get an error:
ORA-01787: only one clause allowed per query block
01787. 00000 - "only one clause allowed per query block"
*Cause:
*Action:
Error at Line: 8 Column: 1
What am I doing wrong?
criminals:
Name Null? Type
----------- -------- ------------
CRIMINAL_ID NOT NULL NUMBER(6)
LAST VARCHAR2(15)
FIRST VARCHAR2(10)
STREET VARCHAR2(30)
CITY VARCHAR2(20)
STATE CHAR(2)
ZIP CHAR(5)
PHONE CHAR(10)
V_STATUS CHAR(1)
P_STATUS CHAR(1)
crimes:
Name Null? Type
--------------- -------- ---------
CRIME_ID NOT NULL NUMBER(9)
CRIMINAL_ID NOT NULL NUMBER(6)
CLASSIFICATION CHAR(1)
DATE_CHARGED DATE
STATUS CHAR(2)
HEARING_DATE DATE
APPEAL_CUT_DATE DATE
DATE_RECORDED DATE

Fix Your Scalar Subquery in the Having Clause
SELECT first
, last
FROM criminals cls
NATURAL
JOIN crimes
WHERE v_status = 'N'
GROUP BY first
, last
HAVING COUNT(1) >(
SELECT AVG(COUNT(DISTINCT crime_id))
FROM crimes
GROUP BY criminal_id);
The scalar query is malformed in both of your attempts.
I moved the condition WHERE v_status = 'N' to the main query (you are only concerned about criminal whom are non-violent).

Related

Cross Reference Columns ORACLE SQL

I am having trouble selecting all values from a table.
I need to select all vehicles where their vRentTimes value is the same as the times they appear in the Renting table.
So basically just checking if the recordings of rentings are correct.
This is the description of tables:
Vehicle
Name Null? Type
------------ -------- ------------
VPLATENUMBER NOT NULL VARCHAR2(7)
VCOLOR NOT NULL VARCHAR2(10)
VCC NOT NULL NUMBER
VHORSEPOWER NOT NULL NUMBER
VRENTTIMES NUMBER
VEHCATNAME NOT NULL VARCHAR2(20)
Renting
Name Null? Type
------------ -------- -----------
CAFM NOT NULL VARCHAR2(9)
VPLATENUMBER NOT NULL VARCHAR2(7)
OUTDATE NOT NULL DATE
INDATE DATE
I see. vRentTimes is supposed to be a count for the second table. You can use JOIN and `aggregation. To get the rows that do not match:
select v.*, r.cnt
from vehicles v left join
(select VPLATENUMBER, count(*) as cnt
from renting r
group by VPLATENUMBER
) r
on r.VPLATENUMBER = v.VPLATENUMBER
where v.VRENTTIMES <> coalesce(cnt, 0);

How to get the max date in Oracle using a subquery

i have a table named remit_bill and i would like to get the max date from this table using the following query but it keeps on showing me errors.there are several dates under the same bill_no.i want to get the maximum date with coll_amt value.any help with this would be appreciated.
SQL> desc remit_bill
Name Null? Type
------------------------------- -------- ----
SC_CD NOT NULL VARCHAR2(2)
RMT_NO NOT NULL VARCHAR2(6)
RMT_DT DATE
BILL_NO NOT NULL VARCHAR2(6)
COLL_AMT NOT NULL NUMBER(10,2)
Query :
select sum(COLL_AMT) FROM REMIT_BILL AS P
WHERE bill_no = '887332' and rmt_dt=(SELECT MAX(rmt_dt) FROM REMIT_BILL AS P2
where P2.bill_no=P.BILL_NO
--GROUP BY COLL_AMT
)
GROUP BY COLL_AMT
Error Message :
select sum(COLL_AMT) FROM REMIT_BILL AS P
*
ERROR at line 1:
ORA-00933: SQL command not properly ended
SQL>
Image:
try this
select sum(p.COLL_AMT) FROM REMIT_BILL P
WHERE p.bill_no = '887332' and p.rmt_dt=(SELECT MAX(rmt_dt) FROM REMIT_BILL P2
where P2.bill_no=P.BILL_NO
)
GROUP BY p.COLL_AMT

Insert in table, Sequence.nextval not working

I have the following 3 tables,
Data_Excel contains the names, address, city and source of person;
Person table has the name and ID;
I need to insert into person_location the address source, address, city and ID...
I am using the following query :
CREATE SEQUENCE seq
START WITH 6571
MINVALUE 6571
INCREMENT BY 1
CACHE 100
INSERT INTO Person (id,Name,source)
Select (seq.nextval),p_name,source
FROM Data_Excel
WHERE P_Name NOT IN
(SELECT name FROM Person)
GROUP BY P_Name,P_Address,P_city,Source
HAVING count(*) < 2;
but I get the following error.
I am using seq because ID is the primary key in persons but its not auto incrementing. I also tried that but there was an error :
02287. 00000 - "sequence number not allowed here"
*Cause: The specified sequence umber (CURRVAL or NEXTVAL) is inappropriate
here in the statement.
*Action: emove the sequence number.
Try moving the sequence out of the grouping query:
INSERT INTO Person (id,Name,source)
SELECT seq.nextval, p_name,source FROM (
Select p_name,source
FROM Data_Excel
WHERE P_Name NOT IN
(SELECT name FROM Person)
GROUP BY P_Name,P_Address,P_city,Source
HAVING count(*) < 2
);

What is wrong with my select statement?

Here is the question, keep in mind I'm using SQL developer 3....
The Student Services department wants to know how involved each faculty member is when it comes to supplying advice to students outside of class. Supply a list of faculty IDs and the number of students that faculty member is advising. Title the output column for faculty IDs “Faculty ID”, and the output column for the student count as “NumStuds”. Produce output only if the faculty id is less than 100 and the student has a value entered in either the last name or first name field. Present the output in increasing order by faculty ID
This is what I get...
SELECT F_ID AS "Falculty ID" , COUNT S_ID AS "NumStud" FROM student
WHERE ( s_first, s_last, f_id ) IS NOT NULL
AND IS <= 100
ORDER BY F_ID ACD
Then I get error Error starting at line 329 in command:
SELECT F_ID AS "Falculty ID" , COUNT S_ID AS "NumStud" FROM student
WHERE ( s_first, s_last, f_id ) IS NOT NULL
AND IS <= 100
ORDER BY F_ID ACD
Error at Command Line:329 Column:42 Error report: SQL Error:
ORA-00923: FROM keyword not found where expected
00923. 00000 - "FROM keyword not found where expected"
PLEASE HELP!
You cannot do that since you are testing for null value. It should manually be tested.
SELECT F_ID AS "Falculty ID" , COUNT(S_ID) AS "NumStud"
FROM student
WHERE (
s_first IS NOT NULL OR
s_last IS NOT NULL OR
f_id IS NOT NULL
) AND IS <= 100
ORDER BY F_ID ASC
Second, it should ASC for Ascending not ACD
Try:
SELECT F_ID AS "Faculty ID" , COUNT(S_ID) AS "NumStud"
FROM student
WHERE COALESCE( s_first, s_last ) IS NOT NULL AND F_ID < 100
GROUP BY F_ID
ORDER BY F_ID ASC

Join logic from two separate tables in sql

We returned a list of cardID's after a query and those cardID's belong to two tables Student and Personnel. So how can I join those cardID's with Student and Personnel so I can return a table that shows name of Student and Personnel according to cardID's?
Personnel table:
PERSONNELID NUMBER(9,0)
PERSONNELNAME VARCHAR2(20)
PERSONNELSURNAME VARCHAR2(20)
PERSONNELJOB VARCHAR2(40)
PERSONNELCARDID NUMBER(4,0)
Student table:
STUDENTID NUMBER(9,0)
STUDENTNAME VARCHAR2(20)
STUDENTSURNAME VARCHAR2(20)
STUDENTDEPT VARCHAR2(40)
STUDENTFACULTY VARCHAR2(20)
STUDENTCARDID NUMBER(4,0)
CardID table
CARDID NUMBER(4,0)
USERTYPE VARCHAR2(20)
CHARGE NUMBER(3,2)
CREDIT NUMBER(4,2)
PaymentDevice table:
ORDERNO NUMBER
PAYDEVIP NUMBER(8,0)
PAYDEVDATE DATE No
PAYDEVTIME VARCHAR2(8)
CHARGEDCARDID NUMBER(9,0)
MEALTYPE VARCHAR2(10)
I tried to return first 10 person's name and surname that eat at cafeteria on 27/12/2012
SELECT C.CARDID
FROM CARD C, PAYMENTDEVICE P
WHERE P.ORDERNO
BETWEEN (SELECT MIN(ORDERNO)
FROM PAYMENTDEVICE
WHERE PAYDEVDATE='27/12/2012') AND (SELECT MIN(ORDERNO)
FROM PAYMENTDEVICE
WHERE PAYDEVDATE='27/12/2012')+10 AND C.CARDID=P.CHARGEDCARDID;
Our orderNo isn't reset everyday but keeps increasing so we found the min orderNo that day and add 10 to this value to find first 10 person who eat on that day between those order numbers.
So what return from this query:
CARDID
1005
1000
1002
1003
1009
2000
2001
1007
2002
1004
1006
and those some of those cardId (start with 1) are studentCardId and some of them (starts with 2) are PersonnelCardId. So how can I match and write names accordingly?
SELECT *
FROM Personel p INNER JOIN Student s
ON p.PersonnelCardId = s.StudentCardId
INNER JOIN ReturnedQuery rq
ON rq.CardId = p.PersonnelCardId
updated:
SELECT p.PersonnelName, rq.CardId
FROM Personel p INNER JOIN ReturnedQuery rq
ON rq.CardId = p.PersonnelCardId
UNION
SELECT s.StudentName, rq.Cardid
FROM Student s INNER JOIN ReturnedQuery rq
ON s.StudentCardId = rq.Cardid
Your original query is actually pretty fragile. I'd rewrite it like so (and added the needed joins):
WITH First_Daily_Purchase as (SELECT chargedCardId,
MIN(payDevTime) as payDevTime,
MIN(orderNo) as orderNo
FROM PaymentDevice
WHERE payDevDate >=
TO_DATE('2012-12-27', 'YYYY-MM-DD')
AND payDevDate <
TO_DATE('2012-12-28', 'YYYY-MM-DD')
GROUP BY chargedCardId),
First_10_Daily_Purchasers as (SELECT chargedCardId
FROM (SELECT chargedCardId,
RANK() OVER(ORDER BY payDevTime,
orderNo) as rank
FROM First_Daily_Purchase) a
WHERE a.rank < 11)
SELECT a.chargedCardId, b.personnelName, b.personnelSurname
FROM First_10_Daily_Purchasers a
JOIN Personnel b
ON b.personnelCardId = a.chargedCardId
UNION ALL
SELECT a.chargedCardId, b.studentName, b.studentSurname
FROM First_10_Daily_Purchasers a
JOIN Student b
ON b.studentCardId = a.chargedCardId
(Have a working SQL Fiddle - generally bullet-proofing this took me a while.)
This should get you the first 10 people who made a purchase (not the first 11 purchases, which is what you were actually getting). This of course assumes that payDevTime is actually stored in a sortable format (if it isn't you have bigger problems than this query not working quite right).
That said, there's a number of troubling things about your schema design.