I have 2 tables on my Oracle DB
One with a product list
PRODUCT_ID - PRODUCT_NAME - PRODUCT_PRICE
1 P_1 50
2 P_2 60
3 P_3 70
4 P_4 80
And one with the orders
CLIENT_ID - PRODUCT_ID - ORDER_PRICE
1 1 50
2 3 60
3 2 70
4 2 70
I need to make a query so it returns the product_list table but ordered by the most frequent Product_id in the orders table. So in this case the Product ID=2 must be first on the list.
I have found some examples but i cant find something that will work for this case.
You can use subquery for aggregation on orders table to find count for each product id and then left join it with the product_list table to use the calculated count for ordering.
select p.*
from product_list p
left join (
select product_id,
count(*) as cnt
from orders
group by product_id
) o on p.product_id = o.product_id
order by o.cnt desc nulls last;
LEFT Join is used since not all products could have orders and we need to find the count of orders for each product.
GROUP BY is used because we use the aggregate count() to find the occurrence of orders for a given Product.
ORDER BY DESC is used so the count is ordered highest count of product orders first to lowest. However when ties exist, we don't know what order will be returned as a second level of order by is not defined. Could be order We could add a Product_ID so they are low to high after that...
.
SELECT PL.Product_ID, PL.Product_Name, PL.Product_Price, count(O.Product_ID) cnt
FROM Product_List
LEFT JOIN Orders O
on O.Product_ID = PL.Product_ID
GROUP BY PL.Product_ID, PL.Product_Name, PL.Product_Price
ORDER BY cnt Desc
Related
Scenario :
Join Table ORDER with Table COST
where COST has multiple rows for a single reference from Table ORDER
Desired outcome:
Return single row per Order with its associated costs.
ID NAME PRICE GST
1 Book 100 10
2 CD 50 5
Ex:
Table ORDER
ID NAME COST
1 Book 110
2 CD 55
Table COST
ID ORDER_ID COST_TYPE VALUE
1 1 PRICE 100
2 1 GST 10
3 2 PRICE 50
4 2 GST 5
LEFT OUTER JOIN returns multiple rows when below condition is used
SELECT * from ORDER
LEFT OUTER JOIN COST
ON ORDER.ID = COST.ORDER_ID
select o.id, o.name, c.price, c.gst
from order o left outer join
( select order_id,
sum(case when cost_type = 'PRICE' then value end) as price,
sum(case when cost_type = 'GST' then value end) as gst
from cost
group by order_id
) c
on o.id = c.order_id
;
So Select ORDER.ID, COST.COST_TYPE, COST.VALUE from ORDERS LEFT OUTER JOIN COST ON ORDER.ID = COST.ORDER_ID and COST.COST_TYPE = 'PRICE'
If you don't specify COST_TYPE then it will return multiple rows because ORDER_ID repeats on your COST TABLE.
This is what i found working in my case.
Had to use 2 LEFT OUTER JOIN's and alias to get it working
SELECT ID, NAME, PRICE.value as PRICE, GST.value as GST
from ORDER
LEFT OUTER JOIN COST as PRICE
ON ORDER.ID = COST.ORDER_ID
AND PRICE.COST_TYPE = 'PRICE'
LEFT OUTER JOIN COST as GST
ON ORDER.ID = COST.ORDER_ID
AND GST.COST_TYPE = 'GST'
I have show the total product sale on the basis YTD (Year to Date), QTD(Quarter to Date) and MTD (Month to Date). The thing is I have to show only one from those. Only one output can be seen on the basis of selection i.e. like we have radio buttons to select one from many. Here also a input is given to select and on the basis of that input the output is generated. The input can be any YTD,QTD or MTD. The output is generated on the basis of input. I don't how to calculate a column output where the input can be vary.
I have a Product Table-
Product_ID Product_name Price
1 Mobile 200
2 T.V. 400
3 Mixer 300
I have a Sales table like this-
Product_ID Sales_Date Quantity
1 01-01-2015 30
2 03-01-2015 40
3 06-02-2015 10
1 22-03-2015 30
2 09-04-2015 10
3 21-05-2015 40
1 04-06-2015 40
2 29-07-2015 30
1 31-08-2015 30
3 14-09-2015 30
And my ouput column contains 3 columns that are-
Product_id, Product_Name and Total_Amount.
The column Total_Amount(quantity*price) have to calculate sale on the basis of input given by user i.e.,
IF it is YTD then it should calculate the total sale from Starting Date of Year ( 01-01-2015) to the current_date(sysdate),
IF it is QTD then in which quarter the current date is falling i.e if current month is september then from 1 July to current_date(sysdate),
IF it is MTD then in which month the current date is falling to the current_date(sysdate).
Can anyone help. Thanks!!!
-- step 1
create or replace view my_admin
as
select 'YTD' element, product_id, sum(quantity) sum_quantity
from sales
where Sales_date between trunc(sysdate,'Y') and sysdate
group by product_id
union
select 'QTD', product_id, sum(quantity) sum_quantity
from sales
where Sales_date between trunc(sysdate,'Q') and sysdate
group by product_id
union
select 'MTD', product_id, sum(quantity) sum_quantity
from sales
where Sales_date between trunc(sysdate,'MM') and sysdate
group by product_id
-- step 2
select element, p.product_name, (sum_quantity * p.PRICE) agregate
from my_admin a
inner join products p on a.product_id = p.product_id
where element = (:input)
My presumption is that you have 3 radio buttons(variables :YTD,:QTD,:MTD in my example) where just one value at a time can be picked by the user the rest will be null.
You can use a something like this to get what you want:
select SUM(a.QTY*B.PRICE) from PRODUCTS a
inner join SALES B on a.PRODUCT_ID=B.PRODUCT_ID
where
(:YTD is null or B.SALES_DATE between '01-JAN-15' and sysdate)
and
(:QTD is null or TO_CHAR(B.SALES_DATE, 'YYYY-Q')=TO_CHAR(sysdate, 'YYYY-Q'))
and
(:MTD is null or TO_CHAR(B.SALES_DATE, 'MM')=TO_CHAR(sysdate, 'MM'));
You can test it here sqlfiddle
I have a query which returns list of SIMs. Each SIM is linked to a Customer. The SIMs are in T_SIM table and Customers are in T_CUSTOMER table. There can be more than one SIM linked to a single Customer. When returning the SIMs it returns the Customer details also.
The T_SIM table will have a foreigh key to T_CUSTOMER table.
The issue is:
First run the query by requesting top 100 records by doing order by CUSTOMER_CODE in ascending order.
Now run the same query by requesting top 1000 records by doing order by CUSTOMER_CODE in ascending order.
Here in point #2, in the results of 1000 records the first 100 records are not same as in point #1 result. The records got shuffled. The order is not consistent.
To resolve this I have used ROWID along with order by CUSTOMER_CODE.
But the solution is not accepted by the client.
Could you please suggest any other alternative to resolve the issue. The data type of CUSTOMER_CODE is VARCHAR2
Below is the query:
SELECT TT.SIM_ID,
TT.IMSI,
TT.MSISDN,
TT.SECONDARY_MSISDN,
TT.CUSTOMER_ID,
TT.SIM_STATE,
TCU.CUSTOMER_CODE
FROM T_SIM TT
LEFT OUTER JOIN T_CUSTOMER TCU
ON TT.CUSTOMER_ID = TCU.CUSTOMER_ID
WHERE 1 = 1
AND TT.SIM_ID IN
(SELECT SIM_ID
FROM
(SELECT *
FROM
(SELECT Z.*,
ROWNUM RNUM
FROM
(SELECT TT.SIM_ID
FROM T_SIM TT
LEFT OUTER JOIN T_CUSTOMER TCU
ON TT.CUSTOMER_ID = TCU.CUSTOMER_ID
WHERE 1 =1
ORDER BY TCU.CUSTOMER_CODE ASC
) Z
WHERE ROWNUM <= 1000
)
WHERE RNUM >= 0
)
)
ORDER BY TCU.CUSTOMER_CODE ASC
The result in both the cases is done order by CUSTOMER_CODE but the SIMS belonging to them are not coming in the same order.
The problem is that first you are limiting number of rows when selecting from t_sim (so these are selected randomly) , and just then you are ordering your output.
So what you should do, is to remove ROWNUM<1000 from inner query and
put it on the very top level like this:
select * from
( TT.SIM_ID,
TT.IMSI,
TT.MSISDN,
TT.SECONDARY_MSISDN,
TT.CUSTOMER_ID,
TT.SIM_STATE,
TCU.CUSTOMER_CODE
FROM T_SIM TT
LEFT OUTER JOIN T_CUSTOMER TCU
ON TT.CUSTOMER_ID = TCU.CUSTOMER_ID
WHERE 1 = 1
AND TT.SIM_ID IN
(SELECT SIM_ID
FROM
(SELECT *
FROM
(SELECT Z.*,
ROWNUM RNUM
FROM
(SELECT TT.SIM_ID
FROM T_SIM TT
LEFT OUTER JOIN T_CUSTOMER TCU
ON TT.CUSTOMER_ID = TCU.CUSTOMER_ID
WHERE 1 =1
ORDER BY TCU.CUSTOMER_CODE ASC
) Z
)
WHERE RNUM >= 0
)
)
ORDER BY TCU.CUSTOMER_CODE ASC
) where rownum<1000
Because first you want to make complete ordered result set and just then display 1000 top records of sim cards ordered by customer_code.
So I have a table like this. This is a standard Order header - Order Detail table:
order id order_line
----------- -----------
100 1
100 2
100 3
101 1
102 1
103 1
103 2
104 1
105 1
Now, how can I make a SELECT that will only pick the orders that only have one line?
In this case I don't want orders 100 and 103.
Thanks!
Tiago
Counting lines using "group by order_id" is a good solution, however counting is not needed, simpler Max function works fine:
select order_id from orders
group by order_id
having max(order_line)=1;
In case order_line has consecutive values further "optimization" is possible:
select order_id from orders
where order_line <= 2
group by order_id
having max(order_line)=1;
Group by the order_id and take only those having 1 record per group
select order_id
from orders
group by order_id
having count(*) = 1
If you need the complete record then do
select t1.*
from orders t1
join
(
select order_id
from orders
group by order_id
having count(*) = 1
) t2 on t1.order_id = t2.order_id
You can try following query too :
select order_id , order_line
from Order_Detail
group by order_id ,order_line
having count(order_id)<2;
Folks we have one wired requirement in HIVE and we are not able to write query for the same
Basically we have following data.
CUSTOMER_NAME PRODUCT_NAME PRICE OCCURANCE ID
customer1, product1, 20, 1
customer1, product2, 30, 2
customer1, product1, 25, 3
customer1, product1, 20, 1
customer1, product2, 20, 2
Basically what we have to do is list the average price for (customer_name,product_name) for single occurance.
e.g. for combination (customer1,product1) price for product1 is
25+20/2(no of distinct occurences for customer(1 and 3)) = 22.5. But as we want to group by PRODUCT_NAME also we donot know how to calculate the distinct occurance. I have marked the query with [] bracket where we feel we need to do some change.
Other aspect is the inner query here we want to select customers where their average price will fall in to top 5 for distinct occurrencs. ( This works properly as group by clause is having only one attribute CUSTOMER_NAME)
select customer_name,product_name,[sum(price)/count(distinct(occurance_id))]
from customer_prd cprd
Join (select customer_name,sum(price)/count(distinct(occurance id))
order by sum group
by customer_name limit 5)
cprdd
where cprd.customer_name = cprdd.customer_name group by cprd.customer_name,cprd.product_name
output expected.
customer1,product1, 20 (avg for occurance ID 1) + 25(average for occurance ID 2)/2 = 22.5
customer1,product2, 30 + 20/2 = 25
If I understand correctly, it seems like the only trouble here is that you have duplicates. If you remove duplicate occurrences, then it's a simple group by and average:
select customer_name, product_name, avg(price)
from (
select distinct customer_name, product_name, price, occurance_id from cprd
) t
group by customer_name, product_name