I have 2 sub queries which are repeated and are very long so I want to give it a name and then refer that name in the query as mentioned in https://stackoverflow.com/a/3058938/6700081.
I have a Customers table with ID, Name, OrderID
I have the Orders table with ID (this is the order ID so it is also the Foreign key), Price, Order_Date
This is my original query which is working fine:
SELECT CUSTOMERS.name, ORDERS.price FROM
CUSTOMERS INNER JOIN ORDERS
ON (CUSTOMERS.ORDER_ID = ORDERS.ID)
WHERE ORDERS.PRICE = (SELECT MAX(ORDERS.PRICE) from ORDERS where ORDERS.ORDER_DATE <= (SELECT ADD_MONTHS((SELECT MIN(ORDER_DATE) FROM ORDERS), 12*10) from ORDERS WHERE ROWNUM = 1))
AND ORDERS.ORDER_DATE <= (SELECT ADD_MONTHS((SELECT MIN(ORDER_DATE) FROM ORDERS), 12*10) from ORDERS WHERE ROWNUM = 1);
I tried to change it to a named query as below:
WITH MAX_ORDER_DATE as (SELECT ADD_MONTHS((SELECT MIN(ORDER_DATE) FROM ORDERS), 12*10) from ORDERS WHERE ROWNUM = 1),
WITH MAX_ORDER_PRICE as (SELECT MAX(ORDERS.PRICE) from ORDERS where ORDERS.ORDER_DATE <= (MAX_ORDER_DATE))
SELECT CUSTOMERS.name, ORDERS.price FROM
CUSTOMERS INNER JOIN ORDERS
ON (CUSTOMERS.ORDER_ID = ORDERS.ID)
WHERE ORDERS.PRICE = (MAX_ORDER_PRICE)
AND ORDERS.ORDER_DATE <= (MAX_ORDER_DATE);
But I get an error related to invalid table name. What is wrong with this query?
Your corrected query:
WITH MAX_ORDER_DATE AS (
SELECT ADD_MONTHS((SELECT MIN(ORDER_DATE) FROM ORDERS), 12*10) AS max_date
FROM ORDERS
WHERE ROWNUM = 1
),
MAX_ORDER_PRICE AS (
SELECT MAX(ORDERS.PRICE) AS max_price
FROM ORDERS
WHERE ORDERS.ORDER_DATE <= (SELECT max_date FROM MAX_ORDER_DATE)
)
SELECT c.name, o.price
FROM CUSTOMERS c
INNER JOIN ORDERS o
ON c.ORDER_ID = o.ID
WHERE
o.PRICE = (SELECT max_price FROM MAX_ORDER_PRICE) AND
o.ORDER_DATE <= (SELECT max_date FROM MAX_ORDER_DATE);
The main issues I noticed with your syntax were that you repeated WITH for each common table expression, when you only need to state it once at the beginning of the definitions. Also, if you want to use the single values you define in the two CTEs, you should use a subquery against those CTEs. Finally, I added aliases to the columns you select in the CTEs.
Related
I have the following table (tb1):
I need to create a query that consist of:
Select the oldest Date_created having Status 001.
Should not select a PCR if the same PCR having status 002.
For the table above, this query should return the following table:
Can anyone help me how to create it?
Final query:
select q2.id,q2.PCR,q2.status, q2.date_created from (select pcr, min(date_created) date_created from table1 t1 where not exists (select * from table1 t2 where t1.pcr = t2.pcr and t2.status = '002') group by pcr) q1 inner join (select * from table1) q2 on q1.PCR = q2.PCR and q1.date_created = q2.date_created
I have two tables, Table A has an ID and an Event Date and Table B has an ID, a Description and an Event Date.
Not all IDs in Table A appear in Table B and some IDs appear multiple times in Table B with different Descriptions for each event.
The Description in Table B is an attribute that can change over time, the Event date in Table B is the date that a given ID's Description changes from its default value (kept in another table) to the new value.
I want to find the Description in Table B that matches the Event Date in Table A so, for example
Table Sample Data
A1234 would return Green and A4567 would return Null
I can't create tables here so I need to be able to this with a query.
This query will select last description from before the event:
SELECT * FROM (
SELECT tabA.id, tabA.event_date, tabB.description,
ROW_NUMBER() OVER(PARTITION BY tabB.id ORDER BY tabB.event_date DESC) rn
FROM Table_A tabA
LEFT JOIN Table_B tabB ON tabA.id = tabB.id AND tabB.event_date <= tabA.event_date
) WHERE rn = 1
If I understand well your need, this could be a way:
select a.id, description
from tableA A
left join
(select id,
description,
event_date from_date,
lead(event_date) over (partition by id order by event_date) -1 as to_date
from tableB
) B
on (A.id = B.id and a.event_date between b.from_date and b.to_date)
The idea here is to evaluate, for each row in tableB the range of dates for which that row, and its description, is valid; given this, a simple join should do the job.
You can left join tables like:
select a.ID , b1.DESCRIPTION
from TABLE_A a
left join TABLE_B b1 on a.ID = b1.id and a.EVENT_DATE > b1.EVENT_DATE
left join TABLE_B b2 on a.ID = b2.id and b1.EVENT_DATE < b2.EVENT_DATE and a.EVENT_DATE > b2.EVENT_DATE
where b1.id is null or b2.EVENT_DATE is null;
I have query in which i used partition of avoid the duplicate value for particular column , but still it is giving duplicate row below i am mention my query in which i used partition
SELECT iol.M_product_id as faultyProduct , iol.SERIALNO,iol.M_product_id as newproduct, ma.Description,
mp.M_Product_category_id ,mi.issotrx, co.C_BPartner_ID,
ROW_NUMBER() OVER(PARTITION BY ma.Description ORDER BY iol.M_product_id DESC) rn
FROM M_inoutline iol
inner join M_inout mi ON (iol.m_inout_id = mi.m_inout_id)
inner join C_Order co ON (co.c_order_id = mi.c_order_id )
inner Join M_AttributeSetInstance ma ON (ma.m_attributesetinstance_id =iol.m_attributesetinstance_id)
inner join M_Product mp ON (mp.m_product_id = iol.m_product_id)
where mp.m_product_category_id= 1000447 AND mi.issotrx = 'Y';
Please help me out
For me it looks you want to do:
select * from (/*YOUR QUERY*/) where rn = 1;
I'd like to isplay the name, address and phone number for the clients who has not made any reservations for the past two months.
The tables are :
CLIENT (
ClientNo,
Name,
Sex,
DOB,
Address,
Phone,
Email,
Occupation,
MaritalStatus,
Spouse,
Anniversary
)
RESERVATION
ResNo,
ResDate,
NoOfGuests,
StartDate,
EndDate,
ClientNo,
Status
)
I tried:
SELECT Name, Address, Phone, ResNo
FROM Client C, Reservation R
WHERE Date_Column >= ResDate R(MONTH, -3, GETDATE())
ORDER BY Name DESC
You need an outer join, with all conditions in the join, and then filter out all successful joins:
SELECT C.*
FROM Client C
LEFT JOIN Reservation R ON C.ID = R.ID -- outer join
AND R.ResDate >= add_months(TRUNC(SYSDATE) + 1, 2) -- condition in join
WHERE R.ID IS NULL -- only return missed joins
ORDER BY Name ASC
You want the missed joins - ones where there are no reservations at all given the conditions. Such missed joins have all-nulls in the joined table's columns, so filtering on (one of) those columns being null will return clients who don't have any such reservations.
Try to make your where condition like
ResDate >= add_months(TRUNC(SYSDATE) + 1, 2)
Also you are missing the JOIN for your table. So you need to put the JOIN like
SELECT C.Name, C.Address, C.Phone, R.ResNo, R.ResDate
FROM Client C INNER JOIN Reservation R ON C.ID = R.ID --Change the column for Joing as per your table structure
WHERE R.ResDate >= add_months(TRUNC(SYSDATE) + 1, 2))
ORDER BY Name ASC;
Consider a database schema with three relations:
Employee (*eid:integer*, ename:string, age:integer, salary:real)
Works (*eid:integer*, *did:integer*, pct_time:integer)
Department(*did:integer*, dname:string, budget:real, managerid:integer)
Query the view above to find the name of the manager who manages most employees. If thesame employee works in several departments, that employee is counted once in each of the
departments. The manager is included in the count the same as all other employees, i.e., based
on his or her records in the Works table.
Why do I get this error:
ORDER BY SUM (EmpCount) DESC)
*
ERROR at line 6:
ORA-00907: missing right parenthesis
Here is my query:
SELECT distinct(MgrName)
FROM ManagerSummary
WHERE MgrID = (SELECT MgrID
FROM ManagerSummary
GROUP BY MgrID
ORDER BY SUM (EmpCount) DESC
LIMIT 1 );
The view is:
CREATE VIEW ManagerSummary (DeptName, MgrID, MgrName, MgrSalary, EmpCount)
AS SELECT d.dname, d.managerid, e.ename, e.salary,
(SELECT COUNT (w.did)
FROM works w
WHERE w.did = d.did
GROUP BY w.did)
FROM employee e, department d WHERE d.managerid = e.eid;
Thank you
Update: Changing LIMIT 1 for WHERE ROWNUM = 1 doesn't help
Try this
SELECT DISTINCT (MgrName)
FROM ManagerSummary
WHERE MgrID = (SELECT MgrId
FROM ( SELECT MgrId, SUM (empcount) AS maxemp
FROM ManagerSummary
GROUP BY MgrId
ORDER BY SUM (empcount) DESC)
WHERE ROWNUM = 1)
You seem to want the name of the manager that has the most employees.
My guess is that you can do this in Oracle as:
select ms.MgrName
from (select ms.*
from ManagerSummary ms
order by EmpCount desc
) ms
where rownum = 1;
It is hard for me to envision a table called ManagerSummary that would have more than one row per MgrId. That's why I don't think aggregation is necessary.
SELECT mgrname
FROM (SELECT mgrname, numemps
FROM (SELECT mgrname, count(*) numemps
FROM mgrsummary
GROUP BY mgrname)
ORDER BY NUMEMPS desc);
Just noticed - this is based on a view. This is ~not~ going to perform well.