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

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
)

Related

Finding the most frequently occurring combination

I have two table with name Orders and Products,The order table contains the number of specific orders made by a customer and the products included in that order is in the Products table.
My requirement is to get the number of total orders against the most frequently coming products.
means for these products product 1,Product 2, product 3 what is the total orders,If an order contains 10 Products which contains Product 1 ,Product 2 and Product 3 that order should be counted.
For an order_id there can be multiple products will be there and i'm confused on how to get this result.Can anyone share or suggest a solution on how to get this?
I'm using PostgreSQL.
Below is the sample query ,
SELECT
"Orders"."order_id",pr.product_name
FROM
"data"."orders" AS "Orders"
LEFT JOIN data.items i On i."order_id"="Orders"."order_id"
LEFT join data.products pr on pr."product_id"=i."product_id"
WHERE TO_CHAR("Orders"."created_at_order",'YYYY-MM-DD') BETWEEN '2019-02-01' AND '2019-04-30'
ORDER BY "Orders"."order_id"
Desired Result will be like this(3 columns),The most purchased product combination with number of occurring orders.
Product 1, Product 2,Product 3,etc..... , Number Of Orders
This is the sample data output,Need the product list which is purchased in combination the most.(As of now i have given only 3 columns for sample but it may vary according to the number of PRODUCTS in an order).
and example
SELECT
"Orders"."order_id",
string_agg(DISTINCT pr.product_name,::character varying, ',') AS product_name
count(1) AS product_no
FROM
"data"."orders" AS "Orders"
LEFT JOIN data.items i On i."order_id"="Orders"."order_id"
LEFT join data.products pr on pr."product_id"=i."product_id"
WHERE TO_CHAR("Orders"."created_at_order",'YYYY-MM-DD') BETWEEN '2019-02-01' AND '2019-04-30'
GROUP BY "Orders"."order_id"
ORDER BY count(1);
You can try to use group by clause.
If you want to generally get the number of orders against some products then you can just count the number of orders grouped on the products from product table. Query should look something like this:
SELECT product_id, COUNT(*)
FROM data.products
GROUP BY product_id
ORDER BY COUNT(*)
LIMIT 1;
Hope this helps!
Try to use GROUP BY and take MOST counted value as below-
SELECT
pr.product_name,
COUNT(DISTINCT Orders.order_id)
FROM
"data"."orders" AS "Orders"
LEFT JOIN data.items i On i."order_id"="Orders"."order_id"
LEFT join data.products pr on pr."product_id"=i."product_id"
WHERE TO_CHAR("Orders"."created_at_order",'YYYY-MM-DD') BETWEEN '2019-02-01' AND '2019-04-30'
GROUP BY pr.product_name
ORDER BY COUNT(DISTINCT Orders.order_id) DESC
LIMIT 1 -- You can use the LIMIT or NOT as per requirement

SQL Beginner: Getting items from 2 tables (+grouping+ordering)

I have an e-commerce website (using VirtueMart) and I sell products that consist child products. When a product is a parent, it doesn't have ParentID, while it's children refer to it. I know, not the best logic but I didn't create it.
My SQL is very basic and I believe I ask for something quite easy to achieve
Select products that have children.
Sort results by prices (ASC/DSC).
SELECT * FROM Products INNER JOIN Prices ON Products.ProductID = Prices.ProductID ORDER BY Products.Price [ASC/DSC]
Explanation:
SELECT - Select (Get/Retrieve)
* - ALL
FROM Products - Get them from a DB Table named "Products".
INNER JOIN Prices - Selects all rows from both tables as long as there is a match between the columns in both tables. Rather, JOIN DB Table "Products" with DB Table "Prices".
ON - Like WHERE, this defines which rows will be checked for matches.
Products.ProductID = Prices.ProductID - Your match criteria. Get the rows where "ProductID" exists in both DB Tables "Products" and "Prices".
ORDER BY Products.Price [ASC/DSC] - Sorting. Use ASC for Ascending, DSC for Descending.
This table design is subpar for a number of reasons. First, it appears that the value 0 is being used to indicate lack of a parent (as there's no 0 ID for products). Typically this will be a NULL value instead.
If it were a NULL value, the SQL statement to get everything without a parent would be as simple as this:
SELECT * FROM Products WHERE ParentID IS NULL
However, we can't do that. If we make the assumption that 0 = no parent, we can do this:
SELECT * FROM Products WHERE ParentID = 0
However, that's a dangerous assumption to make. Thus, the correct way to do this (given your schema above), would be to compare the two tables and ensure that the parentID exists as a ProductID:
SELECT a.*
FROM Products AS a
WHERE EXISTS (SELECT * FROM Products AS b WHERE a.ID = b.ParentID)
Next, to get the pricing, we have to join those two tables together on a common ID. As the Prices table seems to reference a ProductID, we can use that like so:
SELECT p.ProductID, p.ProductName, pr.Price
FROM Products AS p INNER JOIN Prices AS pr ON p.ProductID = pr.ProductID
WHERE EXISTS (SELECT * FROM Products AS b WHERE p.ID = b.ParentID)
ORDER BY pr.Price
That might be sufficient per the data you've shown, but usually that type of table structure indicates that it's possible to have more than one price associated with a product (we're unable to tell whether this is true based on the quick snapshot).
That should get you close... if you need something more, we'll need more detail.
use the below script if you are using ssms.
SELECT pd.ProductId,ProductName,Price
FROM product pd
LEFT JOIN price pr ON pd.ProductId=pr.ProductID
WHERE EXISTS (SELECT 1 FROM product pd1 WHERE pd.productID=pd1.ParentID)
ORDER BY pr.Price ASC
Note :neither of your parent product have price in price table. If you want the sum of price of their child product use the below script.
SELECT pd.ProductId,pd.ProductName,SUM(ISNULL(pr.Price,0)) SUM_ChildPrice
FROM product pd
LEFT JOIN product pd1 ON pd.productID=pd1.ParentID
LEFT JOIN price pr ON pd1.ProductId=pr.ProductID
GROUP BY pd.ProductId,pd.ProductName
ORDER BY pr.Price ASC
You will have to use self-join:
For example:
SELECT * FROM products parent
JOIN products children ON parent.id = children.parent_id
JOIN prices ON prices.product_id = children.id
ORDER BY prices.price
Because we are using JOIN it will filter out all entries that don't have any children.
I haven't tested it, I hope it would work.

Get last record making multiple searches in the same table

I have one table called Products.
Fields
product_id
Type (IN or OUT)
Date (date of registration)
I have several entries in the table, with entries and product outputs with their respective dates.
How do I find products that do not have OUTPUT movement after the LAST ENTRY?
I already tried:
SELECT Products.product_id, Products.Type, MAX(Products.Date)
FROM Products PRODUCTS_1
LEFT OUTER JOIN Products PRODUCTS
ON PRODUCTS_1.Product_Id = PRODUCTS.Product_Id
AND PRODUCTS_1.Type='O'}
WHERE (PRODUCTS.Type='I')
AND (PRODUCTS_1.Date>PRODUCTS.Date)
GROUP BY Products.product_id, Products.Type;
This query will list all products for which the latest entry is I. I think that's what you are asking for.
SELECT p.product_id
FROM products p
GROUP BY p.product_id
HAVING MAX(Date) = MAX(CASE WHEN Type = 'I' THEN Date END)

Oracle SQL - Problem displaying using the foreign key

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
;

how do i use 'distinct' properly for my product query

I have a product catalog with
a product table (tblProducts : ProductID),
a product category table (tblProductCategories : CatID),
a product sub-category table (tblProductSubCategories : SubCatID), and
a xref table (tblProdXCat : ProductID,CatID,SubCatID)
that links the products to cats and subcats.
Products can be linked to multiple cats and/or subcats.
How can I query and get distinct products only (no product duplicated in result set)?
Microsoft SQL Server please.
Thanks!
I assume your tblProducts table is a table of distinct products, so you aren't asking how to select distinct products from thence.
If you mean how to get distinct products from tblProdXCat, then it's probably as simple as SELECT DISTINCT ProductID FROM tblProdXCat.
But maybe you want a complete information about the products rather than simply their IDs. In that case you could just INNER JOIN that list of distinct ProductID values against tblProducts:
SELECT p.*
FROM Products p
INNER JOIN (SELECT DISTINCT ProductID FROM tblProdXCat) x
ON p.ProductID = x.ProductID
If that is still not what you want then you may need to clarify your request.
select distinct productID from tblProducts
Put all the joining ambiguity into the WHERE clause.
SELECT *
FROM Products
WHERE ProductID in
(
SELECT ProductId
FROM Products JOIN ...
)