Produce one row in an Oracle sql query using group_by - sql

I'm using Oracle 10.g. I have a table, LIB_BOOK, containing a listing of books in a library. There are multiple copies of many of the books. I'd like to produce a report that lists all the books with more than one copy. I've constructed a query that lists the books, but I can't find a way to get only one row for the result.
Select
title
, copy_number
, isbn_10
, category
, book_pk
, max(copy_number)
From LIB_BOOK
Group by
title
, copy_number
, isbn_10
, category
, book_pk
Order by copy_number desc
;
As you can see in the data result below, I get the results for "Conversations with God - Book 1" listed seven times. I'd like that book to be listed only once with a "7" as the copy_number.
I took the first 32 rows of the query result, exported it to Excel and pasted the image below.
How do I construct a query to result in only one row per book, and avoid books with only one copy (copy_number > 1)?
Thanks for looking at this.

Try this
Select
title
, copy_number
, isbn_10
, category
, book_pk
, copy_number
From LIB_BOOK lib
join (select title,max(copy_number) as maxcopynumber
from LIB_BOOK group by title) maxcopy on lib.title = maxcopy.title and lib.copy_number = maxcopy.maxcopynumber
Order by lib.copy_number desc
;

You need to remove copy_number() and book_pk from the group by:
Select title, isbn_10, category,
max(copy_number)
From LIB_BOOK
Group by title, isbn_10, category
Order by max(copy_number) desc;
I'm not sure what you want for book_pk, so I just removed it from the select.

It looks like you only want to list the duplicate books, no matter what category, copy number etc. So group by book (isbn and title) and count, then remove books with less than 2 copies in your HAVING clause:
select
title
, isbn_10
, max(copy_number) as max_copy_number
, count(*) as number_of_copies
from lib_book
group by title, isbn_10
having count(*) > 1
order by count(*) desc;
You can use the unsupported WM_CONCAT to list categories and book pks:
select
title
, isbn_10
, max(copy_number) as max_copy_number
, count(*) as number_of_copies
, wm_concat(distinct category) as categories
, wm_concat(book_pk) as book_pks
...

Note that you are getting getting multiple rows because some of the fields which you are grouping by are different for the same book like copy number and book pk ...
Please try the below query:
SELECT *
FROM (SELECT TITLE,
COPY_NUMBER,
ISBN_10,
CATEGORY,
BOOK_PK,
COPY_NUMBER,
ROW_NUMBER() OVER (PARTITION BY ISBN ORDER BY COPY_NUMBER DESC) RN
FROM LIB_BOOK) X
WHERE RN = 1

Related

combine 2 query statements into one

hi I have 2 sql query and I would like to run it in one query
so to explain about the query the first one to get the most frequent brand names
then the second one to get the most item sold with empty brand name column
now I want to combine both so I can get the list of products where they have empty brand name column but the name of product contains the list of brands I have
here is my 2 query
select brand_name as top_brands
from "catalog-my"."catalog_my_20210425"
where store_merchant_id like '%lazada%' and brand_name in ( 'HP' ,'Acer','VAKIND','Casio','Lenovo','BF1 Soul',
'Sony','Lenovo','Samsung','Bosch','Xiaomi',
'Panasonic','Dell','Rondaful','Toshiba','UCUC',
'zanzea','CAMERON SINO','ZZOOI','Canon',
'Philips','LEGO','Glamorousky','ZeroQiQi','Baosity','Huawei'
,'Alloet','Hontinga','OME','Jotun','Yamaha')
group by brand_name
and the second query
SELECT name
,item_sold_30d
,brand_name
,category_name
,product_url
FROM (
SELECT DISTINCT b.name,b.item_sold_30d , b.brand_name ,b.category_name, a.product_url, ROW_NUMBER() OVER (PARTITION BY b.name,b.item_sold_30d , b.brand_name ,b.category_name ORDER BY a.product_url) as rowId
FROM "dasync"."outputs_lazada_my"a
INNER JOIN "catalog-my"."catalog_my_20210425"b ON b.name = a.name
WHERE b.name like '%'||brand_name||'%' and b.brand_name =''
ORDER BY b.item_sold_30d DESC
) dt
WHERE dt.rowId = 1
limit 10;
please help me to combine these 2

How to group this query with repeated values on one column and the other column containing no repeated data?

I'm practicing SQL and I'm trying to do a query of the best seller by section in a shop, I have this query so far:
select idrama, nombre, apellido, max(valortotal)
from(
select personarama.idrama, persona.nombre, persona.apellido,sum(detalle.cantidad*precio.valor) as valortotal
from persona,factura,precio,detalle, personarama
where persona.idpersona=factura.idvendedor
and personarama.idpersona=persona.idpersona
and factura.numfactura=detalle.numfactura
and precio.referencia=detalle.referencia
and factura.fecha between precio.fechaini and precio.fechafin
group by persona.idpersona, personarama.idrama, persona.nombre, persona.apellido
order by 4 DESC
) as vendedorRama
group by idrama, nombre, apellido;
when I execute the query I get the sellers by section and the amount of money they have sold.
And I need to get the best seller by section, and the only way to do this, is grouping by only idrama, but with this solution I cannot get the name and firstname of the seller. How could I group this data without losing those columns?
You can use window function like this:
select DISTINCT idrama, nombre, apellido, max(valortotal) OVER (PARTITION BY idrama) AS 'Max_of_valortotal'
from(
select personarama.idrama, persona.nombre, persona.apellido,sum(detalle.cantidad*precio.valor) as valortotal
from persona,factura,precio,detalle, personarama
where persona.idpersona=factura.idvendedor
and personarama.idpersona=persona.idpersona
and factura.numfactura=detalle.numfactura
and precio.referencia=detalle.referencia
and factura.fecha between precio.fechaini and precio.fechafin
group by persona.idpersona, personarama.idrama, persona.nombre, persona.apellido
order by 4 DESC
) as vendedorRama

SQL nested aggregate functions MAX(COUNT(*))

I'm trying to select max(count of rows).
Here is my 2 variants of SELECT
SELECT MAX(COUNT_OF_ENROLEES_BY_SPEC) FROM
(SELECT D.SPECCODE, COUNT(D.ENROLEECODE) AS COUNT_OF_ENROLEES_BY_SPEC
FROM DECLARER D
GROUP BY D.SPECCODE
);
SELECT S.NAME, MAX(D.ENROLEECODE)
FROM SPECIALIZATION S
CROSS JOIN DECLARER D WHERE S.SPECCODE = D.SPECCODE
GROUP BY S.NAME
HAVING MAX(D.ENROLEECODE) =
( SELECT MAX(COUNT_OF_ENROLEES_BY_SPEC) FROM
( SELECT D.SPECCODE, COUNT(D.ENROLEECODE) AS COUNT_OF_ENROLEES_BY_SPEC
FROM DECLARER D
GROUP BY D.SPECCODE
)
);
The first one is working OK, but I want to rewrite it using "HAVING" like in my second variant and add there one more column. But now 2nd variant don't output any data in results, just empty columns.
How can I fix it ? Thank YOU!)
This query based on description given in comments and some suggestions, so it may be wrong:
select -- 4. Join selected codes with specializations
S.Name,
selected_codes.spec_code,
selected_codes.count_of_enrolees_by_spec
from
specialization S,
(
select -- 3. Filter records with maximum popularity only
spec_code,
count_of_enrolees_by_spec
from (
select -- 2. Count maximum popularity in separate column
spec_code,
count_of_enrolees_by_spec,
max(count_of_enrolees_by_spec) over (partition by null) max_count
from (
SELECT -- 1. Get list of declarations and count popularity
D.SPECCODE AS SPEC_CODE,
COUNT(D.ENROLEECODE) AS COUNT_OF_ENROLEES_BY_SPEC
FROM DECLARER D
GROUP BY D.SPECCODE
)
)
where count_of_enrolees_by_spec = max_count
)
selected_codes
where
S.SPECCODE = selected_codes.spec_code
Also query not tested and some syntax errors are possible.

Find incorrect records by Id

I am trying to find records where the personID is associated to the incorrect SoundFile(String). I am trying to search for incorrect records among all personID's, not just one specific one. Here are my example tables:
TASKS-
PersonID SoundFile(String)
123 D10285.18001231234.mp3
123 D10236.18001231234.mp3
123 D10237.18001231234.mp3
123 D10212.18001231234.mp3
123 D12415.18001231234.mp3
**126 D19542.18001231234.mp3
126 D10235.18001234567.mp3
126 D19955.18001234567.mp3
RECORDINGS-
PhoneNumber(Distinct Records)
18001231234
18001234567
So in this example, I am trying to find all records like the one that I indented. The majority of the soundfiles like '%18001231234%' are associated to PersonID 123, but this one record is PersonID 126. I need to find all records where for all distinct numbers from the Recordings table, the PersonID(s) is not the majority.
Let me know if you need more information!
Thanks in advance!!
; WITH distinctRecordings AS (
SELECT DISTINCT PhoneNumber
FROM Recordings
),
PersonCounts as (
SELECT t.PersonID, dr.PhoneNumber, COUNT(*) AS num
FROM
Tasks t
JOIN distinctRecordings dr
ON t.SoundFile LIKE '%' + dr.PhoneNumber + '%'
GROUP BY t.PersonID, dr.PhoneNumber
)
SELECT t.PersonID, t.SoundFile
FROM PersonCounts pc1
JOIN PersonCounts pc2
ON pc2.PhoneNumber = pc1.PhoneNumber
AND pc2.PersonID <> pc1.PersonID
AND pc2.Num < pc1.Num
JOIN Tasks t
ON t.PersonID = pc2.PersonID
AND t.SoundFile LIKE '%' + pc2.PhoneNumber + '%'
SQL Fiddle Here
To summarize what this does... the first CTE, distinctRecordings, is just a distinct list of the Phone Numbers in Recordings.
Next, PersonCounts is a count of phone numbers associated with the records in Tasks for each PersonID.
This is then joined to itself to find any duplicates, and selects whichever duplicate has the smaller count... this is then joined back to Tasks to get the offending soundFile for that person / phone number.
(If your schema had some minor improvements made to it, this query would have been much simpler...)
here you go, receiving all pairs (PersonID, PhoneNumber) where the person has less entries with the given phone number than the person with the maximum entries. note that the query doesn't cater for multiple persons on par within a group.
select agg.pid
, agg.PhoneNumber
from (
select MAX(c) KEEP ( DENSE_RANK FIRST ORDER BY c DESC ) OVER ( PARTITION BY rt.PhoneNumber ) cmax
, rt.PhoneNumber
, rt.PersonID pid
, rt.c
from (
select r.PhoneNumber
, t.PersonID
, count(*) c
from recordings r
inner join tasks t on ( r.PhoneNumber = regexp_replace(t.SoundFile, '^[^.]+\.([^.]+)\.[^.]+$', '\1' ) )
group by r.PhoneNumber
, t.PersonID
) rt
) agg
where agg.c < agg.cmax
;
caveat: the solution is in oracle syntax though the operations should be in the current sql standard (possibly apart from regexp_replace, which might not matter too much since your sound file data seems to follow a fixed-position structure ).

Top N results grouped Oracle SQL

I want to write a query that allows me to only get the specific data I want and nothing more.
We will use TV's as an example. I have three brands of TVs and I want to see the top ten selling models of each brand. I only want to return 30 rows. One solution is unions, but that can get messy fast. Ideally there would be a WHERE ROWNUM grouping by situation.
SELECT
A.Brand
, A.Model
, A.Sales
FROM
( SELECT
TV.Brand
, TV.Model
, SUM(TV.SALES) AS SALES
FROM TV_TABLE as TV
ORDER BY
TV.Brand
, SALES DESC
) A
WHERE ROWNUM <10
In my code above I will get the top 10 total results from the inner query, but not 10 from each Grouping.
What I want to see is something like this:
Brand: Model: Sales
Sony: x10: 20
Sony: X20: 18
Sony: X30: 10
VISIO: A40: 40
VISIO: A20: 10
This is an oversimplified example, in practice I'll need to have 20-50 gropings and would like to avoid downloading all of the data and using a Pivot feature.
select Brand, Model, SALES
from(
select Brand, Model, SALES,row_number()over(partition by Brand order by SALES desc) rn
from (
SELECT TV.Brand, TV.Model,SUM(TV.SALES) AS SALES,
FROM TV_TABLE as TV
group BY TV.Brand,TV.Model
)a
)b
where rn <= 10
SELECT TV.Brand, TV.Model, SUM(TV.SALES) AS SALES
FROM TV_TABLE TV
group by TV.Brand, TV.Model
order by SUM(TV.SALES) desc, TV.Brand
limit 30