Counting and Joining in SQL (oracle) - sql

My database contains 2 tables called products and product_categories.
Product_categories contain category_id and category_name
Products contain category_id and other irrelevant info for this question.
I need to count the number of products using category_id from the products table and also display their name which is in the product_categories table.
Select * FROM product_categories
displays :
category_id, category_name
1 CPU
2 Video Card
3 RAM
4 Mother Board
5 Storage
And
Select * FROM products
displays (condensed):
category_id
399.77 564.89 1
481.56 554.99 1
4058.99 5499.99 2
3619.14 4139 2
2505.04 3254.99 2
... UPTO CATEGORY_ID 5
Current statement :
SELECT category_id , COUNT (1) AS "TOTAL"
FROM products
GROUP BY category_id;
Output:
Category_id, total
1 70
2 50
5 108
4 60
DESIRED RESULT: I need to display the category id followed by category name and finally the total number of products.

Join those tables:
select p.category_id,
c.category_name,
count(*) as total
from products p join product_categories c on c.category_id = p.category_id
group by p.category_id,
c.category_name
You might want to turn it to outer join if you want to display categories that don't exist in the products table.

Related

Query returns more rows

I have two tables. product_type listing name of products with product id. There are 5 product types which have same product id (1) as they are shared along with 4 other product types with unique product ids (2 to 9). Other table is product. It has the list of customer ids along with what product template id associated with it.
I want to get a list of products which are being used by customer. But I am getting a list with duplicate product rows if there are two customers using the same product. I just want to get a unique list of products being used by all the customers.
Product Table
Product Product_id
AML 1
EDU 1
EXM 1
JEXM 2
JFSA 3
Customer Table
Customer_id Product_id
112 1
113 2
114 1
115 3
116 4
117 2
The query:
SELECT CTE.ProductType, CTE.PRODUCT_ID, DECODE(CT.PRODUCT_ID,NULL,0,1) AS HasCustomer
FROM (
SELECT
LISTAGG(pt.product_type, ', ') WITHIN GROUP (ORDER BY pt.product_type) as ProductType,
pt.PRODUCT_ID
FROM product_type pt
group by pt.PRODUCT_ID) CTE
JOIN CUSTOMER CT ON CT.PRODUCT_ID = CTE.PRODUCT_ID;
Blockquote
I think you want:
SELECT c.customer_id,
LISTAGG(p.product, ', ') WITHIN GROUP (ORDER BY p.product) as products
FROM customers c JOIN
products p
ON c.PRODUCT_ID = p.PRODUCT_ID
GROUP BY c.customer_id;
For each customer, this will give the list of products for the customer.
I based this on your sample data. I don't see the relationship between your query and the sample data.
EDIT:
If you want all products used by any customer, then simply do:
select distinct c.product_id
from customers c;

SQL number of products

I have two tabels :
--Products--
idProduct PK
Category FK
Amount
Name
--Category--
idCategory PK
Category Name
if i have 20 products of different categories for example 3 cars 5 planes 9 types of food
how do i get all of them in a new joined table like this
Category Name (from --Category--) Amount of every product (from --Products--)
Cars 3
Planes 9
And so on , i don't have a table with all the elements from each category so what should i do ?
You may looking for simple join with aggregate function
SELECT CategoryName,COUNT(p.Category ) AS [Amount of every product ]
FROM Category c
INNER JOIN Product p ON c.idCategory = p.Category
GROUP BY CategoryName

Query to consolidate multiple columns into 1

we have a database query that queries for all products on our website.
It currently has 10,000 products and some of these products reside in 3 categories of products which the category information is stored in a tracking table.
This then means our queries return 3 instances of those products.
What Im wondering is. is it possible to query a database and return a single instance of these products but place the category names into a single column like a list ?
Is this known as an aggregate function? or is this some sort of sub query that will consolidate the information into 1 column for use.
We are using MSSQL 2012
table products
id
product_name
display_name
table tracking
id
product_id
category_id
view_order
table categories
category_id
category_name
red tshirt with an id 1
categories
Mens Wear with id of 1
Tshirts with id of 2
clothing with id of 3
what we would like as the output is
Product_name category
Red Tshirt Mens Wear,Tshirts,Clothing
instead of
Product_name category
Red Tshirt Mens Wear
Red Tshirt Tshirts
Red Tshirt clothing
which is what we are getting now
The following TSQL using the For XML trick to create a CSV field will do the trick
with combined (product_name, category) as (
select product_name, category_name
from
products
inner join tracking on products.id = tracking.product_id
inner join categories on categories.id = tracking.category_id
)
select
product_name,
stuff((select distinct ',' + nullif(category,'')
from combined t2 where t2.product_name = t1.product_name
for XML PATH(''),TYPE).value('.','VARCHAR(MAX)'),1,1,'') as category
from combined t1

Text search of a many-to-many data relation

I know this must have been answered before here, but I simply can't find a matching question.
Using a LIKE '%keyword%', I want to search a many-to-many data relationship in a MSSQL database and reduce it to a one-to-one result set. The two tables are joined through a linking table. Here's a very simplified version of what I'm talking about:
Books:
book_ id title
1 Treasure Island
2 Poe Collected Stories
3 Invest in Treasure Islands
Categories:
category_id name
1 Children
2 Adventure
3 Horror
4 Classic
5 Money
BookCategory:
book_id category_id
1 1
1 2
1 4
2 3
2 4
3 5
What I want to do is search for a phrase in the title (e.g. '%treasure island%') and get matching Books records that contain the search string and the single highest matching Categories record that goes with each book -- I want to discard the lesser category records. In other words, I'm looking for this:
book_id title category_id name
1 Treasure Island 4 Classic
3 Invest in Treasure Islands 5 Money
Any suggestions?
Try this. Filter your lookup table, then join:
With maxCategories AS
(select book_id, max(category_id) as category_id from BookCategory group by book_id)
select Books.book_id, Books.Title, Categories.category_id, Categories.name
from Books
inner join maxCategories on (Books.book_id = maxCategories.book_id)
inner join Categories on (Categories.category_id = maxCategories.category_id)
where Books.title like '%treasure island%'
Try:
select * from
(select b.*,
c.*,
row_number() over (partition by bc.book_id
order by bc.category_id desc) rn
from Books b
join BookCategory bc on b.book_id = bc.book_id
join Categories c on bc.category_id = c.category_id
where b.name like '%treasure island%') sq
where rn=1

complex sql query from 4 tables

I am developing an online travel guide with a lot of hotels. Each hotel belongs to a specific category, has a lot room types and each of hotel room has different price per season. I want to make a complex query from 4 tables in order to get the total number of hotels per hotels category where the minimum price of each hotel rooms is between 2 values which are adjusted by a slider.
My tables look like:
Categories
id_category
category_name
Hotels
id_hotel
hotel_name
category_id
......
hotels_room_types
id_hotels_room_type
hotel_id
room_type_id
......
hotels_room_types_seasons
hotels_room_types_id
season_id
price
......
for example some values of category_name are: Hotels, apartments, hostels
I would like my results table to have two fields like the following:
Hotels 32
apartments 0
hostels 5
I tried the following query but it returns the total number of all hotels per category, not the number of hotels where the minimum price of their rooms is between the price range.
SELECT c.category_name, count( DISTINCT id_hotel ) , min( price ) min_price
FROM categories c
LEFT JOIN hotels w ON ( c.id_category = w.category_id )
LEFT JOIN (
hotels_room_types
INNER JOIN hotels_room_types_seasons ON hotels_room_types.id_hotels_room_types = hotels_room_types_seasons.hotels_room_types_id)
ON w.id_hotel = hotels_room_types.hotel_id
GROUP BY c.category_name
HAVING min_price >=10 AND min_price <=130
Could anyone help me how to write the appropriate query?
Thanks!!!
SELECT Categories.Name, COUNT(DISTINCT ID_Hotel) [Count]
FROM Hotels
INNER JOIN Categories
ON Category_ID = ID_Category
INNER JOIN
( SELECT Hotel_ID, MIN(Price) [LowestPrice]
FROM hotels_room_types
INNER JOIN hotels_room_types_seasons
ON id_hotels_room_type = hotels_room_types_id
-- CONSIDER FILTERING BY SEASON HERE
GROUP BY Hotel_ID
) price
ON price.Hotel_ID = Hotels.ID_Hotel
WHERE LowestPrice BETWEEN 10 AND 130 -- OR WHATEVER YOUR PARAMETERS ARE
GROUP BY Categories.Name
I have no idea what RDBMS you are using but I do not know any where your query would work. The problem you were having with the Min Price (I assume) is because you are applying the logic after grouping by category, so you are counting all hotels where the category has a lowest price between 10 and 130, not where the hotel has a room with the lowest price between 10 and 130.
select
c.Category_name,
count(*) NumHotels
from
( select distinct
byRoomType.hotel_id
from
hotels_room_types_seasons bySeason
join hotels_room_types byRoomType
on bySeason.hotels_room_types_id = byRoomType.id_hotels_room_type
where
bySeason.Price between LowPriceParameter and HighPriceParameter
) QualifiedHotels
join Hotels
on QualifiedHotels.hotel_id = Hotels.id_hotel
join Categories c
on category_id = c.id_category