Cross Reference Columns ORACLE SQL - 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);

Related

Joining tables with recent date for each row then weighted averaging

There are three tables, such as equip_type , output_history, and time_history in Oracle DB.
Is there a way to join the three tables as shown below at (1) and then to get weighted average as shown below at (2)?
--equip_type table and the date
CREATE TABLE equip_type (
EQUIP_TYPE VARCHAR(60),
EQUIP VARCHAR(60)
);
INSERT INTO equip_type VALUES ('A','e1');
-- output_history and data
CREATE TABLE output_history (
EQUIP VARCHAR(60),
MODEL VARCHAR(60),
Data1 VARCHAR(60),
QUANTITY NUMBER(10)
);
INSERT INTO output_history VALUES ('e1','m1','20180103',10);
INSERT INTO output_history VALUES ('e1','m1','20180106',20);
--time_history table and data
CREATE TABLE time_history (
EQUIP VARCHAR(60),
MODEL VARCHAR(60),
Data2 VARCHAR(60),
time NUMBER(10)
);
INSERT INTO time_history VALUES ('e1','m1','20180101',6);
INSERT INTO time_history VALUES ('e1','m1','20180105',5);
(1) How to get joined table as below?
EQUIP MODEL DATE1 QUANTITY DATE2 TIME TYPE
---- ---- ---------- ------ -------- ---- ----
e1 m1 20180103 10 20180101 6 A
e1 m1 20180106 20 20180105 5 A
For each row in OUTPUT_HISTORY, *the most recent row at the point of the DATE1*in TIME_HISTORY is joined.
(2) Then, With the joined table above, how to get weighted average of TIME?
(QUANTITY * TIME) / sum of QUANTITY group by TYPE, MODEL
for example,(10×6 + 20×5)÷(10+20) for equip type A and model m1
One method uses analytic functions to get the most recent record and then simple aggregation
select sum(quantity * time) / sum(quantity)
from output_history oh left join
(select th.*,
row_number() over (partition by equip, model order by date2 desc) as seqnum
from time_history th
) th
on oh.equip = th.equip and oh.model = th.model and th.seqnum = 1
group by equip, model;

GROUP BY affecting WHERE clause

I have a SQL query where I want to see claims where there is no service type associated with any of the lines. My query below is returning the one line where it meets the criteria. However, there is another line with a service type which means I don't want to see this. Because of the group by my query is seeing line and returning it and then looking at line two separately and removing it
select distinct a.claim_id,
count(a.receipt_id) as Count_Receipts,
sum(a.billed_amount) as Total_Billed_Amount,
(case
when a.service_type_id is null then
count(a.receipt_id)
else 0
end) test
from cd_roc_claim_item a,
cd_hospital b ,
cd_Claim_header c
where a.hospital_id = b.hospital_id
and a.claim_id=c.claim_id (+)
and b.hos_cat_id='PUBL'
and c.claim_status is null
and a.claim_id='123456'
group by a.claim_id,
a.service_type_id
having count(a.receipt_id) =1
and sum(a.billed_amount) in
('80','160','240','320','400','480','560','640','720','800')
;
If you just want to report the claims where there are no values for service_type in any claim item:
select ci.claim_id
, count(ci.receipt_id) as count_receipts
, sum(ci.billed_amount) as total_billed_amount
, count(*) as claim_items
from cd_roc_claim_item ci
left join cd_hospital ho
on ho.hospital_id = ci.hospital_id
left join cd_claim_header cl
on cl.claim_id = ci.claim_id
where cl.claim_status is null
group by ci.claim_id
-- , ci.service_type_id -- Edit (following comments): this was part of the problem
having count(ci.service_type_id) = 0
and sum(ci.billed_amount) in (80, 160, 240, 320, 400, 480, 560, 640, 720, 800);
CLAIM_ID COUNT_RECEIPTS TOTAL_BILLED_AMOUNT CLAIM_ITEMS
---------- -------------- ------------------- -----------
1 2 160 2
The problem is the hospital category, because every claim item could be for a different hospital with a different category. Do you want to see only claims where all items are for hospital category PUBL, or where there is at least one, or what?
Test setup:
create table cd_hospital
( hospital_id integer primary key
, hos_cat_id varchar2(10) );
create table cd_claim_header
( claim_id varchar2(10) primary key
, claim_status varchar2(10) );
create table cd_roc_claim_item
( claim_item_id integer generated always as identity primary key
, claim_id references cd_claim_header not null
, hospital_id references cd_hospital not null
, billed_amount number not null
, service_type_id integer
, receipt_id integer );
insert into cd_hospital (hospital_id, hos_cat_id) values (1, 'PUBL');
insert into cd_hospital (hospital_id, hos_cat_id) values (2, 'PRIV');
insert into cd_claim_header(claim_id, claim_status) values (1, null);
insert into cd_claim_header(claim_id, claim_status) values (2, 'CLOSED');
insert into cd_roc_claim_item (claim_id, hospital_id, billed_amount, service_type_id, receipt_id)
select ch.claim_id, ho.hospital_id, 80, null, 1
from cd_claim_header ch
cross join cd_hospital ho
where ch.claim_id = 1
union all
select ch.claim_id, ho.hospital_id, 640, 123, 1
from cd_claim_header ch
cross join cd_hospital ho
where ch.claim_id = 2;
Edit in response to comments:
To include a case where a claim has items with and without a service type, we'll update one row:
update cd_roc_claim_item set service_type_id = null
where claim_id = 2 and hospital_id = 1;
Now the test data looks like this:
select ci.claim_id, ch.claim_status, ci.hospital_id, ho.hos_cat_id, ci.service_type_id, ci.receipt_id
from cd_roc_claim_item ci
join cd_claim_header ch
on ch.claim_id = ci.claim_id
join cd_hospital ho
on ho.hospital_id = ci.hospital_id
order by ch.claim_id;
CLAIM_ID CLAIM_STATUS HOSPITAL_ID HOS_CAT_ID SERVICE_TYPE_ID RECEIPT_ID
---------- ------------ ------------ ---------- ---------------- -----------
1 2 PRIV 1
1 1 PUBL 1
2 CLOSED 2 PRIV 123 1
2 CLOSED 1 PUBL 1
As I understand it, you want to report claim 1 (aggregated to one row) because none of its items have a service type. Claim 2 should not be shown, because one of its items has a service type.

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

Subquery having issues

I am having one issue with sub query. I have to pass multiple ids to my sub query..but with my query i am not getting correct result...
Here is the My sample data and my table structure..
Employee Table:
------------------------
EMPLOYEE_ID NOT NULL NUMBER(16)
EXTERNAL_ID_1 VARCHAR2(200)
EXTERNAL_ID_2 VARCHAR2(200)
JOB_PROFILE_TYPE VARCHAR2(4)
FIRST_NAME NOT NULL VARCHAR2(200)
MIDDLE_NAME VARCHAR2(200)
Alignment Table :
-------------------------
ALIGNMENT_ID NOT NULL NUMBER(16)
TEAM_ID NOT NULL NUMBER(16)
EMPLOYEE_ID NUMBER(16)
ALIGNMENT_NAME NOT NULL VARCHAR2(200)
EXTERNAL_ID_1 VARCHAR2(200)
STATUS NOT NULL VARCHAR2(4)
STATUS_CHANGE_DATE NOT NULL DATE
MANAGER_ALIGNMENT_ID NUMBER(16)
Event table :
-------------------
EVENT_ID NOT NULL NUMBER(16)
EMPLOYEE_ID NOT NULL NUMBER(16)
AFFILIATION_ID NUMBER(16)
CUSTOMER_ID NUMBER(16)
EXTERNAL_ID_1 VARCHAR2(200)
Sample data :
ALIGNMENT_ID ALIGNMENT_NAME EMPLOYEE_ID ROLE MANAGER_ALIGNMENT_ID
1006034672 SII-KRN-BANG-A01 17452000001661 REP 1006034513
1006034673 SII-KRN-BANG-A02 18910000219453 REP 1006034513
1006034674 SII-KRN-BANG-A03 60000001963804 REP 1006034513
1006034675 SII-KRN-BANG-A05 60000001963706 REP 1006034514
1006034676 SII-KRN-BANG-A06 18910000081856 REP 1006034514
1006034677 SII-KRN-BANG-B01 60000001963699 REP 1006034513
My Query :
SELECT *
FROM event ev
INNER JOIN employee e ON e.employee_id=ev.employee_id
INNER JOIN alignment a ON e.employee_id=a.employee_id AND alignment_id in(:alignment_id)
Description :
I have the data stored in alignment table with child records and parent records. In alignment table I have the data alignment_id and manager alignment_id.
For each rep there should one manager.(manager_alignment_id).
I have to integrate this query to front end..
In front end I have drop down values and will select multiple ids to pass to this query...
if the selection for alignment_id(rep) then no problem. If they will select manager_alignment_id then how to pass this value to mu query.
I am using oracle 11g version.
This may be the query you're looking for:
SELECT *
FROM employee E
INNER JOIN alignment A ON A.employee_id = E.employee_id
AND (A.manager_alignment_id = <Your value here>
OR A.alignment_id = <Your value here>)
This query returns every rows corresponding to the defined manager_alignment_id or alignment_id.
Hope this will help you.

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.