Query to consolidate multiple columns into 1 - sql

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

Related

Return stock in a warehouse even if there is no row for that given stock

I have 5 different tables:
Toasters: product name (foreign key to products and primary key), slots, serial
Microwaves: product name (same as toaster), wattage
Products: product name (primary key)
Stock: product (fk to product), warehouse (fk to warehouse), amount
Warehouse: name (primary key)
toasters and microwaves are child tables of products (although its not using postgres inheritance, since there are issues with it). They represent different models of toasters (simplified to just slots and wattage here). Every toaster and microwave has exactly 1 entry in the products table.
Now the goal is to create a query that essentially gives me an amount of all products across all warehouses for a given list of product names. The problem is, that some warehouses may not have a stock entry for a certain product. They also have either one stock per product or none.
I have managed to make it work for a single warehouse:
--join together all 3 product tables and select all desired products
WITH selIProducts AS(
SELECT
--Get the products category by checking if the table is part of the query
(CASE
WHEN toasters IS NOT NULL THEN 'toasters'
WHEN microwaves IS NOT NULL THEN 'microwaves'
ELSE 'ERROR'
END) as category,
products.name as productName,
*
FROM products
--I need a full join to include everything
FULL JOIN toasters ON toasters.name=products.name
FULL JOIN microwaves ON microwaves.name=products.name
WHERE
products.name IN (
'TOASTMASTER 3000',
'TOASTMASTER 3000Rev01',
'A3452 Ultra Microwave Oven',
)
),
warehouseStock AS
(
--only works with one inventory
SELECT * FROM STOCK
WHERE stock.warehouse='WH-1'
)
-- left join to ensure all item categories are included
SELECT COALESCE(warehouseStock.amount,0) as amount,* FROM selProducts
LEFT JOIN warehouseStock ON selIProducts.itemId=warehouseStock.item
It tried replacing WHERE stock.warehouse='WH-1' with WHERE stock.warehouse IN ('WH-1','WH-2') but that doesn't work since the desired product types are only joined once, instead of once per warehouse.
The final result should look like this:
Warehouse productName amount wattage slots category
WH-1 TOASTMASTER 3000 0 null 2 toasters
WH-1 TOASTMASTER 3000Rev01 1 null 3 toasters
WH-1 A3452 Ultra Microwave Oven 1 3000 null microwave
WH-2 TOASTMASTER 3000 2 null 2 toasters
WH-2 TOASTMASTER 3000Rev01 0 null 3 toasters
WH-2 A3452 Ultra Microwave Oven 0 3000 null microwave
I don't know how I am I should get postgres to return a null when there isn't a stock in a given warehouse.
Does anybody have any ideas?
You seem to want all products and all warehouses. That suggests a cross join to generate the rows:
SELECT v.warehouse, p.productname,
COALESCE(s.amount, 0) as amount
FROM selProducts p CROSS JOIN
(VALUES ('WH-1'), ('WH-2')) v(warehouse) LEFT JOIN
stock s
ON p.itemId = s.item AND v.warehouse = s.warehouse;
You might have another source for the warehouses, if you don't want to list them explicitly.
Add a table of warehouses wanted.
WITH selIProducts AS(
SELECT
--Get the products category by checking if the table is part of the query
(CASE
WHEN toasters IS NOT NULL THEN 'toasters'
WHEN microwaves IS NOT NULL THEN 'microwaves'
ELSE 'ERROR'
END) as category,
products.name as productName,
*
FROM products
--I need a full join to include everything
FULL JOIN toasters ON toasters.name=products.name
FULL JOIN microwaves ON microwaves.name=products.name
WHERE
products.name IN (
'TOASTMASTER 3000',
'TOASTMASTER 3000Rev01',
'A3452 Ultra Microwave Oven',
)
),
warehousesWanted AS
(
SELECT *
FROM Warehouse
WHERE name in ('WH-1', 'WH-2')
)
-- left join to ensure all item categories are included
SELECT COALESCE(warehouseStock.amount,0) as amount, *
FROM selIProducts sp
CROSS JOIN warehousesWanted ww
LEFT JOIN Stock ON Stock.itemId = sp.itemId
and ww.Name = Stock.Warehouse;
You may need to correct ON clause as I'm not sure what are proper column names of your real tables.

SQL Group by for class column

I have two products Green-M and Green-L both share the same productcode 'Clothes' but belong to different classes say Cap and Hat. (They were supposed to be of the same class)
Below are my tables
tbl_Product
ProductName ProductId classic
Green-M 1 2
Green-L 1 3
tbl_size
sizeid sizename
M Medium
L Large
tbl_Class
classid classname
2 cap
3 hat
tbl_ProductCode
Productid Productcode
1 Clothes
I have written the below query to find products that belong to two different classes
select productcode, count(1) from tbl_product p
join tbl_productcode pc on p.productid = pc.productid
group by productcode
having count(1)>1
It gives the below output
Clothes 2
However, it is taking the sizes into consideration.
This is causing an issue because there are products as below
tbl_Product
Product ProductId classid
Yellow - S 1 2
Yellow - M 1 2
Yellow - L 1 2
This will give output
Clothes 3
Which is giving the size count. But I am only looking for products of different classes, irrespective of the number of sizes.
Instead of
COUNT(1)
use
COUNT(DISTINCT ClassId)
That will ignore the different sizes, and just give you the count of how many unique "ClassId" values appear for each ProductId.

Counting and Joining in SQL (oracle)

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.

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