Oracle SQL - Problem displaying using the foreign key - sql

I am trying to display all of the products showing the dates they have been sold but also all of the products that haven't been sold either.
I have two tables: Products and Sales. The column names are:
Products
prod_id
prod_name
Sales
prod_id
date_of_sale
The two tables are linked using the prod_id column but I just cant seem to get the products that have not been sold to display as well as the ones with sales.

I think you need to use a left outer join between Products and Sales:
SELECT p.PROD_ID, p.PRODUCT_NAME, s.DATE_OF_SALE
FROM PRODUCTS p
LEFT OUTER JOIN (SELECT DISTINCT PROD_ID, DATE_OF_SALE
FROM SALES) s
ON (s.PROD_ID = p.PROD_ID)
Can't play with it at the moment but I think that should get what you want. You should get all PROD_ID's and PRODUCT_NAME's from PRODUCTS, and all DATE_OF_SALE from SALES. If there are no DATE_OF_SALE for a product, you should still see the product.
Share and enjoy.

SELECT p.prod_id, p.product_name, s.date_of_sale
FROM products p
, sales s
WHERE s.prod_id(+) = p.prod_id
;

Related

Lookup with duplicate values

This is kind of a complicated question. I have three tables:
A PRODUCTS table
ProductID
ProductName
Product A
Edwardian Desk
Product B
Edwardian Lamp
And a GROUPS table
ProductGroup
ProductID
Group A
Product A
Group A
Product B
Group B
Product C
And a SALES table
Product ID
Sales
Product A
1000
Product B
500
And I need to show the total of Sales per Product Group.
This part I understand; I wrote the query:
SELECT Groups.ProductGroup, SUM(Sales) AS TotalSales
FROM Groups
JOIN Sales
ON Groups.ProductID=Sales.ProductID
GROUP BY Groups.ProductGroup
This is the part that confuses me though: for each group, I need to pull in one of the names of the products in the group. However, it does not matter which name is pulled. So the final data could show:
Group A, Edwardian Desk, 1500
or
Group A, Edwardian Lamp, 1500
How can I pull the name of the product into my query?
I am working in Microsoft SQL Server
There's a number of ways to bring in one of your product's names, a couple of options are to either use an aggregation with a correlated subquery or to to use an apply.
Note, I've used aliases for your table names - doing so is good practice and makes queries more compact and easier to read. Also - presumably this is a contrived example and not your actual tables - but generally it's not a good practice to have column names identical to the table name, so if Sales on table Sales represents a quantity, then just call it Quantity!
select g.ProductGroup,
(select Min(ProductName) from Products p where p.ProductId=g.ProductId) FirstProductAlphabetically,
Sum(s.Sales) as TotalSales
from Groups g
join Sales s on s.ProductID=g.ProductID
group by g.ProductGroup
select g.ProductGroup,
p.ProductName as FirstProductById,
Sum(s.Sales) as TotalSales
from Groups g
join Sales s on s.ProductID=g.ProductID
cross apply (
select top (1) p.ProductName
from Products p
where p.ProductId=g.ProductId
order by ProductId
)p
group by g.ProductGroup
You can add products to the JOIN and use an aggregation function:
SELECT g.ProductGroup, SUM(s.Sales) AS TotalSales,
MIN(p.ProductName)
FROM Groups g JOIN
Sales s
ON g.ProductID = s.ProductID JOIN
Products p
ON p.ProductID = s.ProductId
GROUP BY g.ProductGroup;
Note: I often add two columns, MIN() and MAX() to get two sample names.
I should add. Your sample data has ProductIds that are not in the Products. That suggests a problem with either the question (more likely) or the data model. If you actually have references to non-existent products, then use a LEFT JOIN to Products rather than an inner join.

Sql interrogation that should return products that were sold more than 400 times returns more than that

I'm creating a tutorial based on a "stores" database. This is the practical part to the tutorial. I am trying to get a list of products that have a sold items quantity (qty) more than 400. What's wrong with the code? It should work just fine?
--Show products that have a sold items quantity more than 400
Select prod_name, qty
From products, sales
Where products.prod_id in (select prod_id from sales
Group by prod_id having sum(qty)>400);
The result I get includes products with a quantity less than 400 times. I hope the image is a good enough indicator.
I would recommend writing the query as:
select p.prod_id, p.prod_name, sum(s.qty)
from products p join
sales s
on p.prod_id = s.prod_id
group by p.prod_id, p.prod_name
having sum(s.qty) > 400;
Notes:
Never use commas in the FROM clause. Always use proper, explicit, standard, readable JOIN syntax.
One major issue in your query is the Cartesian product with no filtering.
Aggregate by the unaggregated columns in the SELECT, especially if you are learning SQL.
You have qty in the SELECT. It should be summed up.
you have no aggregation and no join-criteria in the main query, but you don't even need a subquery:
select max(prod_name), products.prod_id, sum(qty)
from products
inner join sales on products.prod_id = sales.prod_id
group by products.prod_id
having sum(qty)>400;
I do not think you need to use sum since you are trying to compare the values of qty for each product. You can do having qty > 400.
select prod_name, qty from products, sales
where products.prod_id in (select prod_id from sales
group by prod_id having qty >400);

Need help for writing query for a marketplace in postgres

I have database for a marketplace which looks like this:
I have different suppliers selling the same product at different price points, also some products are more popular than others in a given location. For example we have product A and product B, and product A is more popular that product B based on how many has already been sold in that location, and for product A we have 3 suppliers. I want my query to show product A from the cheapest seller, then product B from the cheapest seller. I can achieve that with this code:
WITH tem_1 AS (SELECT product_id, MIN(price) AS price FROM product_supplier GROUP BY product_id) ,
tem_2 AS (SELECT product_id, SUM(quantity) AS n_orders FROM orders Group by product_id)
SELECT products.product_id, suppliers.supplier_id, products.name, tem_1.price,
COALESCE(tem_2.n_orders,0) AS quant FROM products
INNER JOIN product_supplier ON product_supplier.product_id = products.product_id
INNER JOIN suppliers ON suppliers.supplier_id = product_supplier.supplier_id
INNER JOIN product_code ON product_code.code_id = products.code_id
INNER JOIN product_crop ON product_crop.product_id = products.product_id
INNER JOIN crops ON crops.crops_id = product_crop.crop_id
INNER JOIN product_tags ON product_tags.product_id = products.product_id
INNER JOIN tags ON tags.tag_id = product_tags.tag_id
INNER JOIN tem_1 ON tem_1.price = product_supplier.price AND tem_1.product_id = products.product_id
LEFT JOIN tem_2 ON tem_2.product_id = products.product_id
WHERE crops.crops_id = 1 AND product_supplier.quantity >= 3 AND tags.tag = 'علف کش'
ORDER BY quant DESC
LIMIT 10;
The problem is, if i have two different suppliers from different locations, selling the same product with the same price, the results show that product twice, but i only want the results from the closest supplier to the user, in this case product 101 from supplier 3 and not the supplier 1.
I think i have to use MIN(ST_Distance("geopoint from user", "geopoint from suppliers")) and LATERAL to have a distance filed, but because i'm using aggregate functions, in order to do a GROUP BY to remove the duplicate results, i have to add all the fields product_id, supplier_id, name, price, ... to the GROUP BY and that won't result in removing the duplicates.
Any suggestion on how to achieve that?
Your query is rather hard to follow. But, distinct on solves your problem. I'm not 100% sure what you want to be distinct, but something like this:
select distinct on (product_id, price) . . .
from . . .
where . . .
order by product_id, price, ST_Distance("geopoint from user", "geopoint from suppliers");
This returns one row per product and price, based on the smallest distance.
If you want the data ordered in a different way, then use this as a subquery or CTE and order by again in the outer query.

Cant sort correctly when use GROUP BY

I Have two tables:
Products (id, product_name, option)
Prices (id, product_id, price, shop, available)
Each product can have several prices that each shop enters.
I want select products and sort them by price(lowest price) low to high.
But this code deos not work correctly:
Select
product_name,
Prices.price
FROM Products
LEFT JOIN Prices ON Prices.product_id=Products.id
AND Prices.available="yes"
GROUP BY product_name
ORDER BY Prices.price
LIMIT 0,10
The above code at first Group products by name then sort them by price
And its my problem.
I dont want to show one product a few times
Is there any solution?
Select
product_name,
MIN(Prices.price) as mprice
FROM Products
LEFT JOIN Prices ON Prices.product_id=Products.id AND Prices.available="yes"
GROUP BY product_name
ORDER BY mprice
LIMIT 0,10
You are close. You only need an aggregation function in the ORDER BY. However, I would also advise you to use table aliases, an INNER JOIN, and single quotes for the string constant:
SELECT p.product_name, MIN(pr.price)
FROM Products p INNER JOIN
Prices pr
ON pr.product_id = p.id
pr.available = 'yes'
GROUP BY p.product_name
ORDER BY MIN(pr.price)
LIMIT 0, 10;
If you GROUP BY you wont get the different prices for the same product. You could check for the MAX value or count them using agregate functions but you wont get your results this way. Also, you should have an intermediary table since a product can be in defferent models with different prices. And I don't get why you use a name attribute. Why don't you just use the product ID? And do something like
SELECT products.product_name, prices.price
FROM products, prices
WHERE products.ID = prices.product_ID;
ORDER BY prices.price ASC

SQL SELECT only the rows not containing ID used in related table

I have two tables with simple relation. One table is list of sales. The second table is list of products. Relation is that in the Sales table is a Product ID that points to the given product.
I need to retrieve the details on the products that were never sold.
Here are links to the two tables:
Table with Products & Table with Sales
If you don't want to click it, the tables look like this:
**SALES**
id
sale_id
product_id
quantity
**PRODUCTS**
id
name
category_id
stock
brand_id
price
color
warranty
So far I have this:
SELECT products.id
FROM products
LEFT JOIN sale_products ON sale_products.product_id = products.id
WHERE products.id NOT IN (sale_products.product_id)
GROUP BY products.id
But this doesn't retrieve anything, although if I take out the NOT then I get all the 17 IDs of the 17 sold items...
So I'd say it either has to be changed around or done with completely different approach..
Any help is much appreciated and welcome.
Try this:
SELECT products.id
FROM products
LEFT JOIN sale_products ON sale_products.product_id = products.id
WHERE sales_products.product_id IS NULL
GROUP BY products.id
You are asking for all products and for each product, either get a sales record or if no sales record found, return NULL for each column in the sales_product table.
SELECT
*
FROM
PRODUCTS P
WHERE
P.ID NOT IN (
SELECT
PRODUCT_ID
FROM
SALES
)