How to visualize the result to show only 3 rows - oracle

I`m trying to show in my table only 3 rows and they need to contain from Calendar_month_number numbers 4,5,6
https://i.stack.imgur.com/SzYgY.png
any suggestions
select s.PROD_ID,t.DAY_NUMBER_IN_MONTH,t.CALENDAR_MONTH_NUMBER,sum(s.AMOUNT_SOLD)
from CUSTOMERS c join SALES s
on c.CUST_ID=s.CUST_ID
join TIMES t
on s.TIME_ID=t.TIME_ID
where s.PROD_ID = 5
and t.TIME_ID BETWEEN '01-APR-00'and '01-JUL-00'
group by s.PROD_ID,t.DAY_NUMBER_IN_MONTH,t.CALENDAR_MONTH_NUMBER
having sum(s.AMOUNT_SOLD) > 0;

Well, apparently this would be
select t.CALENDAR_MONTH_NUMBER,sum(s.AMOUNT_SOLD)
from CUSTOMERS c
INNER JOIN SALES s
on c.CUST_ID=s.CUST_ID
INNER JOIN TIMES t
on s.TIME_ID=t.TIME_ID
where s.PROD_ID = 5 and
t.TIME_ID BETWEEN '01-APR-00'and '01-JUL-00'
group by t.CALENDAR_MONTH_NUMBER
having sum(s.AMOUNT_SOLD) > 0;

Related

To display the names of all students who have secured more than 50 in all subjects that they have appeared in

Write a query to display the names of all students who have secured more than 50 in all subjects that they have appeared in, ordered by student name in ascending order.enter image description here
I have used this below query but didn't getting desired result as it is not comparing the result by grouping the student_id as whole.
Can anyone suggest any changes in query please.
select distinct student_name from student s join mark m on
s.student_id = m.student_id join subject sb
on m.subject_id = sb.subject_id
where m.value IN
(select value from mark m1 join student s1
on m1.student_id = s1.student_id join subject sb1
on m1.subject_id = sb1.subject_id
where value > 50 group by s1.student_id,m1.value, sb1.subject_id)
order by 1;
select student_name
from student join mark using (student_id)
group by student_name
having min(value) > 50
order by student_name;
A sub-query should be avoided if possible. So by having check if the minimum marks scored by a student is greater than 50 , we can say that he has scored more than 50 in all his subjects.
I don't think that you need such a complex subquery. All you need to do is just find out the minimum marks for a student (INNER JOIN ensures that only those subjects are considered, which have been attempted by the student).
Do a simple JOIN between student and marks table on student_id. We do a GROUP BY on the student_id and get minimum_marks for each student. If the minimum_marks > 50, it means that the student has > 50 marks in all the subjects.
Try the following, this will work in MySQL (as per the Original tag by OP):
SELECT s.student_name, MIN(m.value) AS minimum_marks
FROM student s
JOIN mark m ON s.student_id = m.student_id
GROUP BY s1.student_id
HAVING minimum_marks > 50
ORDER BY s.student_name ASC
Edit As per Oracle (since OP edited later), aliased fields/expressions are not allowed in the HAVING clause. Revised query would look like:
SELECT s.student_name, MIN(m.value) AS minimum_marks
FROM student s
JOIN mark m ON s.student_id = m.student_id
GROUP BY s1.student_id
HAVING MIN(m.value) > 50
ORDER BY s.student_name ASC
select student_name from student where student_id in
(select student_id
from (select student_id ,min(value) from mark group by student_id having min(value)>50)
)
order by student_name;
As it is simple by making subquery as shown above.
1.Extract min value that is greater than 50 and create a table and then compare it from the student table.
2.without using any Join operation
select distinct student_name from student,mark
where student.student_id = mark.student_id
having min(value) > 50
group by student_name
order by student_name;
select student_name
from student s inner join mark m
on s.student_id= m.student_id
having min(m.value)>50
group by student_name
order by student_name asc;
select s.student _name from student s join mark m
on s.student_id = m.student_id
group by s.student_name
having min(m.value) > 50
order by s.student_name;
MySQL> select studentid, name,mark from students where mark>20;
select student_name from student
where student_id in (select student_id from mark group by student_id having min(value) > 50)
order by student_name;

Left Outer Join returns duplicate records - Oracle

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'

Re-writing a join query

I have a question concerning Hive. Let me explain to you the scenario :
I am using a Hive action on Oozie; I have a query which is doing
succesive LEFT JOIN on different tables;
Total number of rows to be inserted is about 35 million;
First, the job was crashing due to lack of memory, so I set "set hive.auto.convert.join=false" the query was perfectly executed but it took 4 hours to be done;
I tried to rewrite the order of LEFT JOINs putting large tables at the end, but same result, about 4 hours to be executed;
Here is what the query look like:
INSERT OVERWRITE TABLE final_table
SELECT
T1.Id,
T1.some_field_name,
T1.another_filed_name,
T2.also_another_filed_name,
FROM table1 T1
LEFT JOIN table2 T2 ON ( T2.Id = T1.Id ) -- T2 is the smallest table
LEFT JOIN table3 T3 ON ( T3.Id = T1.Id )
LEFT JOIN table4 T4 ON ( T4.Id = T1.Id ) -- T4 is the biggest table
So, knowing the structure of the query is there a way to rewrite it so that I can avoid too many JOINs ?
Thanks in advance
PS: Even vectorization gave me the same timing
Too long for a comment, will be deleted later.
(1) Your current query won't compile.
(2) You are not selecting anything from T3 and T4, which makes no sense.
(3) Changing the order of tables is not likely to have any impact with cost based optimizer.
(4) Basically I would suggest to collect statistics on the tables, specifically on the id columns, but in your case I got a feeling that id is not unique in more than 1 table.
Add to your post the result of the following query:
select *
, case when cnt_1 = 0 then 1 else cnt_1 end
* case when cnt_2 = 0 then 1 else cnt_2 end
* case when cnt_3 = 0 then 1 else cnt_3 end
* case when cnt_4 = 0 then 1 else cnt_4 end as product
from (select id
,count(case when tab = 1 then 1 end) as cnt_1
,count(case when tab = 2 then 1 end) as cnt_2
,count(case when tab = 3 then 1 end) as cnt_3
,count(case when tab = 4 then 1 end) as cnt_4
from ( select 1 as tab,id from table1
union all select 2 as tab,id from table2
union all select 3 as tab,id from table3
union all select 4 as tab,id from table4
) t
group by id
having greatest (cnt_1,cnt_2,cnt_3,cnt_4) >= 10
) t
order by product desc
limit 10
;

data not retrieved in the same order

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.

Selecting rows that has exactly same data as other table

I have these tables:
Products, Articles, Product_Articles
Lets say, product_ids are: p1 , p2 article_ids are: a1 , a2 , a3
product_articles is:
(p1,a1)
(p1,a2)
(p2,a1)
(p2,a1)
(p2,a2)
(p2,a3)
How to query for product_id, which has only a1,a2, nothing less, nothing more?
UPDATED Try
SELECT p.*
FROM products p JOIN
(
SELECT product_id
FROM product_articles
GROUP BY product_id
HAVING COUNT(*) = SUM(CASE WHEN article_id IN (1, 2) THEN 1 ELSE 0 END)
AND SUM(CASE WHEN article_id IN (1, 2) THEN 1 ELSE 0 END) = 2
) q ON p.product_id = q.product_id
or
SELECT p.*
FROM products p JOIN
(
SELECT product_id, COUNT(*) a_count
FROM product_articles
WHERE article_id IN (1, 2)
GROUP BY product_id
HAVING COUNT(*) = 2
) a ON p.product_id = a.product_id JOIN
(
SELECT product_id, COUNT(*) total_count
FROM product_articles
GROUP BY product_id
) b ON p.product_id = b.product_id
WHERE a.a_count = b.total_count
Here is SQLFiddle demo for both queries
This is an example of a "set-within-sets" subquery. I advocate using aggregation with a having clause for the logic, because this is the most general way to express the relationships.
The idea is that you can count the appearance of the articles within a product (in this case) in a way similar to using a where statement. The code is a bit more complex, but it offers flexibility. In your case, this would be:
select pa.product_id
from product_articles pa
group by pa.product_id
having sum(case when pa.article_id = 'a1' then 1 else 0 end) > 0 and
sum(case when pa.article_id = 'a2' then 1 else 0 end) > 0 and
sum(case when pa.article_id not in ('a1', 'a2') then 1 else 0 end) = 0;
The first two clauses count the appearance of the two articles, making sure that there is at least one occurrence of each. The last counts the number of rows without those two articles, making sure there are none.
You can see how this easily generalizes to more articles. Or to queries where you have "a1" and "a2" but not "a3". Or where you have three of four of specific articles, and so on.
I believe this can be done entirely using relational joins, as follows:
SELECT DISTINCT pa1.PRODUCT_ID
FROM PRODUCT_ARTICLES pa1
INNER JOIN PRODUCT_ARTICLES pa2
ON (pa2.PRODUCT_ID = pa1.PRODUCT_ID)
LEFT OUTER JOIN (SELECT *
FROM PRODUCT_ARTICLES
WHERE ARTICLE_ID NOT IN (1, 2)) pa3
ON (pa3.PRODUCT_ID = pa1.PRODUCT_ID)
WHERE pa1.ARTICLE_ID = 1 AND
pa2.ARTICLE_ID = 2 AND
pa3.PRODUCT_ID IS NULL
SQLFiddle here.
The inner join looks for products associated with the articles we care about (articles 1 and 2 - produces product 1 and 2). The left outer looks for products associated with articles we don't care about (anything article except 1 and 2) and then only accepts products which don't have any unwanted articles (i.e. pa3.PRODUCT_ID IS NULL, indicating that no row from pa3 was joined in).

Resources