passing a parameter into a subquery - sql

i was wondering if it is possible to pass a parameter into a select subquery.
What i want to do is collect some product data from one table and then crossref the weight of the item to it's carriage cost in a shipping table to return a cost.
something like:
select cataloguenumber, productname,
(select shipping.carriagecost
from shipping
where shipping.carriageweight = weight) as carriagecost
from products
Regards
DPERROTT

While the subquery would work, a better, more readable and efficient way to define this would be as follows:
SELECT p.cataloguenumber
, p.productname,
, s.carriagecost
FROM products p
INNER JOIN
shipping s
ON p.weight = s.carriageweight
This assumes that all product weights have a corresponding entry in the shipping table. If that is not the case then change from INNER JOIN to LEFT JOIN and deal with any nulls.

select cataloguenumber, productname, shipping.carriagecost as carriagecost
from products, shipping
where shipping.carriageweight = products.weight
or am I missing something?

SELECT DISTINCT cataloguenumber, productname, shipping.carriagecost
FROM products
LEFT OUTER JOIN shipping
ON shipping.carriageweight = products.weight

Your subquery should only return 1 row, if it returns more then that your query will throw an error in run-time.

This is possible I think, but then you should retrieve the column you want to pass in your parent query.
select cataloguenumber, productname, weight
(select shipping.carriagecost
from shipping
where shipping.carriageweight = weight) as carriagecost
from products

SELECT DISTINCT products.cataloguenumber, products.productname, shipping.carriagecost
FROM products
LEFT JOIN shipping ON shipping.carriageweight = products.weight

Related

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 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.

Add Column to Query From Same Table, Update Values in Duplicated Column?

I'm trying to figure this one out. In this scenario, gas prices from a particular city in this database are increasing, so they will need to raise their prices 20%. I'm supposed to create a query that will display what the new price will be from that city only. Here is what it is supposed to look like:
Here is my code:
Select ProductID, tblProduct.ProductType, Price, SUM((Price *.20)+Price) AS 'Increased Price'
From tblProduct join tblCompany
On tblProduct.CompanyID = tblCompany.CompanyID
Where tblCompany.CompanyID IN
(Select CompanyID
From tblCompany
Where City = 'Kalamazoo')
Order By ProductID
However, when I go to execute the code, I get the following error:
Msg 8120, Level 16, State 1, Line 1
Column 'tblProduct.ProductID' is invalid in the select list because it is not contained in either an aggregate function or the GROUP BY clause.
I can't figure out what I'm doing wrong. Can anyone enlighten me?
You dont really need the SUM function if you are only calculating the 20% price increase...Do this instead
Select ProductID, tblProduct.ProductType, Price, ((Price *.20)+Price) AS 'Increased Price'
From tblProduct join tblCompany
On tblProduct.CompanyID = tblCompany.CompanyID
Where tblCompany.CompanyID IN
(Select CompanyID
From tblCompany
Where City = 'Kalamazoo')
Order By ProductID
Select tblProduct.ProductID, tblProduct.ProductType, tblProduct.Price, SUM((tblProduct.Price *.20)+tblProduct.Price) AS 'Increased Price'
From tblProduct join tblCompany
On tblProduct.CompanyID = tblCompany.CompanyID
Where tblCompany.CompanyID IN
(Select c.CompanyID
From tblCompany c
Where c.City = 'Kalamazoo')
Order By ProductID
The SUM() suggests an aggregation query. You have no GROUP BY, so the initial columns (ProductId, etc.) are not valid.
It is a good idea to use table aliases for queries. These make queries easier to write and to read. So:
Select p.ProductID, p.ProductType, p.Price, ((p.Price * 1.20) AS IncreasedPrice
From tblProduct p join
tblCompany c
On p.CompanyID = c.CompanyID
Where c.City = 'Kalamazoo'
Order By p.ProductID;
In addition, the IN clause is unnecessary. You can just check the city using the JOIN.

Get Product Onhand Quantity

Using sqlite3, I have two tables: products, orders. I want to know how many products are left in the shop.
SELECT pid,
txt,
price,
qty-coalesce((SELECT SUM(qty)
FROM ORDERS
WHERE pid=?),0)
FROM PRODUCTS
WHERE pid=?
This works if I select 1 product, I would like a list of all my products ?
SELECT
P.pid, P.txt, P.price,
P.qty - coalesce((SELECT sum(O.qty) FROM orders O WHERE O.pid = P.pid), 0)
FROM products P
Try this:
SELECT
pid,
txt,
price,
qty-coalesce(
(SELECT sum(qty)
FROM orders
WHERE orders.pid = products.pid),0)
FROM products
I recommend using:
SELECT t.pid,
t.txt,
t.price,
t.qty - IFNULL(qs.qty_sold, 0) 'onhand_qty'
FROM PRODUCTS t
LEFT JOIN (SELECT o.pid,
SUM(o.qty) 'qty_sold'
FROM ORDERS o) qs ON qs."o.pid" = t.pid
WHERE t.pid = ?
While it works, using correllated SELECT statements in the SELECT clause will have the worst performance because they are executing once for every row returned in your query.
IFNULL is preferrable to use in this case compared to COALESCE. COALESCE is intended for checking 2+ values for being null, giving a false impression when someone else reads your code. There isn't any inherent benefit - per the documentation, they are the same.
Reference: SQLite Core Functions