Getting products from SQL query - sql

I'm currently working on a proprietary shopping cart system and was having a few problems with getting products out with the correct pricing.
Basically my table structure is as follows:
Products table: (Only relevant columns are represented)
----------------------------------------------------
productid | product | descr | disporder| list_price|
----------------------------------------------------
1 name desc 1 0.00
2 name desc 4 0.00
3 name desc 2 2.45
Pricing table:
----------------------------------------
priceid | productid | price | variantid|
----------------------------------------
1 1 13.91 1
2 2 54.25 4
3 2 47.23 2
Variants Table:
-------------------------------
variantid | productid | active|
-------------------------------
1 1 Y
2 2 Y
3 2 Y
So, each product can have - and in most cases does have - multiple variants. My current SQL query I have managed to create thus far is:
SELECT
products.productid, product, descr, p.price, i.image_path
FROM
products
LEFT JOIN
pricing AS p
ON
p.variantid = (SELECT variantid FROM variants
WHERE productid = products.productid LIMIT 1)
LEFT JOIN
images_T AS i
ON
i.id = products.productid
GROUP BY
products.productid
ORDER BY
products.disporder
However, my problem arises when a product does not have a variant. If a product does not have a variant associated with it, the price will be in the list_price column of the products table. How would I go about performing a check to see if a product does indeed have a variant. If not, it should effectively bypass the variants table and get the pricing from list_price within the products table.

Yes, CASE is an option, or COALESCE:
SELECT
products.productid, product, descr,
COALESCE(products.list_price, p.price) AS price,
i.image_path
...
Just join both prices and when the first is NULL the other will be selected.

The simplest way is to use a CASE in the SELECT clause, like so:
SELECT
products.productid, product, descr,
CASE
WHEN p.price IS NULL
THEN products.list_price
ELSE p.price
END AS price,
i.image_path
[...]
Since you're left-joining on pricing/variants, p.price should reliably be NULL for products with no variants.
Hopefully that's what you meant by "bypassing" the variants table. :)

You can do a full join with variants table (which will ONLY give you producs which have variants), and then UNION it with a join of producs and pricing where there exists no varian (using AND NOT EXISTS (SELECT 1 from variants WHERE p.productid=v.productid and p.variantid =v.variantid)
Otherwise, use CASE on pricing.price

Related

SQL join to and from dates - return most recent if no match found

I have two tables that I need to join. I have:
LEFT JOIN AutoBAF on (GETDATE() BETWEEN AutoBAF.FromDate and AutoBAF.ToDate)
and I get the expected result. Now if no matching record is found between the two dates (AutoBAF.FromDate and AutoBAF.ToDate) I would like to join the most recent matching record instead.
Can anyone point me in the right direction.
I am using a MS SQL database hosted in Azure.
Small example:
a small example of what I am trying to achieve:
Table Product:
Product | Description
A | Product A
Table Price
Product | FromDate | ToDate | Price
A | 01-01-20 | 31-01-20 | 100
A | 01-02-20 | 28-02-20 | 110
I need a query that will return the price according to the date returned by GETDATE().
If I run the query 15-01-20 I should get:
Product | Description | Price
A | Product A | 100
If I run the query 15-02-20 I should get:
Product | Description | Price
A | Product A | 110
and finally if I run the query 15-03-20 I will have no price in the Price table. Instead of returning null I would like to "fall back" to the most recent known price instead which in this example is 110
This is not the fastest query cause it joins products with all records with future dates. But if your tables are small, it works.
SELECT product.product, product.description, isnull(pr_curr.price, pr_fut.price) as price
FROM product
left join PRICE pr_curr on product.product=pr_curr.product
and GETDATE() BETWEEN pr_curr.FromDate and pr_curr.ToDate
left join PRICE pr_fut on product.product=pr_fut.product
and GETDATE() < pr_fut.FromDate
where pr_fut.FromDate = (
select min(FromDate) from PRICE dates
where dates.product=pr_fut.product and dates.FromDate>GETDATE()
) or pr_fut.FromDate is null
This looks like SQL Server code, which supports lateral joins via the apply keyword. Assuming you want only one match:
from product p outer apply
(select top (1) ab.*
from autobaf ab
where ab.product = p.product and
getdate() <= ab.todate
order by ab.todate desc
) ab
Note that this correlates on the product, which is not part of your question.
If that is not necessary, then you can use:
from t left join
(select top (1) ab.*
from autobaf ab
where getdate() <= ab.todate
order by ab.todate desc
) ab
on 1 = 1
If you know that there is some record in the past, then you can use cross join instead of left join and dispense with the on clause.
SELECT product.product, product.description, isnull(pr_curr.price, pr_fut.price) as price
FROM product
left join PRICE pr_curr on product.product=pr_curr.product
and GETDATE() BETWEEN pr_curr.FromDate and pr_curr.ToDate
left join PRICE pr_fut on product.product=pr_fut.product
and GETDATE() > pr_fut.FromDate
where pr_fut.FromDate = (
select max(FromDate) from PRICE dates
where dates.product=pr_fut.product and dates.FromDate<GETDATE()
) or pr_fut.FromDate is null

SQL Multiple INNER JOINS In One Select-Statement date-wise

I am using this code for inventory management system, in which i want to retrieve stock in hand date-wise from salestb using Three tables
Table Schema
Productmastertb
prod_id,
Product_name
salesdetailstb
sales_id,
Prod_id,
Prod_qty,
billno
salestb
billno
billdate
I need Result something like this
--------------------------------
Product ID | Product Name | Qty
--------------------------------
1 Mouse 10
2 Keyboard 60
3 Headphone 30
---------------------------------
Hope you will find like below solution (date wise qty):
SELECT pm.product_id
,pm.Product_Name
,SUM(sd.Prod_qty) as Qty
,s.billdate
FROM Productmastertb pm
JOIN salesdetailstb as sd ON sd.product_id = pm.product_id
JOIN salestb as s ON sd.billno = s.billno
GROUP BY pm.product_id, pm.Product_Name, s.billdate
Hope it would be helpful to you !
If its not as per your expectation, kindly provide sample output result with partition by date.

How can I SELECT the max row in a table SQL?

I have a little problem.
My table is:
Bill Product ID Units Sold
----|-----------|------------
1 | 10 | 25
1 | 20 | 30
2 | 30 | 11
3 | 40 | 40
3 | 20 | 20
I want to SELECT the product which has sold the most units; in this sample case, it should be the product with ID 20, showing 50 units.
I have tried this:
SELECT
SUM(pv."Units sold")
FROM
"Products" pv
GROUP BY
pv.Product ID;
But this shows all the products, how can I select only the product with the most units sold?
Leaving aside for the moment the possibility of having multiple products with the same number of units sold, you can always sort your results by the sum, highest first, and take the first row:
SELECT pv."Product ID", SUM(pv."Units sold")
FROM "Products" pv
GROUP BY pv."Product ID"
ORDER BY SUM(pv."Units sold") DESC
LIMIT 1
I'm not quite sure whether the double-quote syntax for column and table names will work - exact syntax will depend on your specific RDBMS.
Now, if you do want to get multiple rows when more than one product has the same sum, then the SQL will become a bit more complicated:
SELECT pv.`Product ID`, SUM(pv.`Units sold`)
FROM `Products` pv
GROUP BY pv.`Product ID`
HAVING SUM(pv.`Units sold`) = (
select max(sums)
from (
SELECT SUM(pv2.`Units sold`) as "sums"
FROM `Products` pv2
GROUP BY pv2.`Product ID`
) as subq
)
Here's the sqlfiddle
SELECT SUM(pv."Units sold") as `sum`
FROM "Products" pv
group by pv.Product ID
ORDER BY sum DESC
LIMIT 1
limit 1 + order by
The Best and effective way to this is Max function
Here's The General Syntax of Max function
SELECT MAX(ID) AS id
FROM Products;
and in your Case
SELECT MAX(Units Sold) from products
Here is the Complete Reference to MIN and MAX functions in Query
Click Here

How to select data based on two tables

I have two tables and want to select only the ones where a certain status is 'complete' in the second table. The most important factor is that all shipments need to be completed.
First Table (orders) includes a unique order id and several cells with customer details. For example
Order_id | Name
1001 | John
1002 | Paula
1003 | Ben
The second table (shipments) has all the items a customer ordered and the status whether they were delivered e.g.
Order_id | Shipment_number | Status
1001 | 8004 | complete
1001 | 8003 | processing
1002 | 8005 | complete
1003 | 8008 | processing
1003 | 8007 | processing
1003 | 8009 | complete
I tried it with the following code but unfortunately the results show all order ids where at least one of the associated shipments is 'complete'.
SELECT
order_id,
name
FROM orders
INNER JOIN shipments ON orders.order_id = shipments.order_id
WHERE
shipments.status = 'complete';
I'm pretty new to SQL and really struggling with this. Thanks in advance :)
SELECT Orders.OrderID
FROM orders
WHERE NOT EXISTS (SELECT OrderID
FROM shipments
WHERE status != 'complete' AND
shipments.OrderID = Orders.OrderID)
You can use nested queries to do this:
Write a query to take a count of the shipments.order_id group by order_id, this gives you the total shipments for each order, select the order_id and the count.
Write a query to take a count of the shipments.order_id group by order_id where shipments.status = 'complete', this gives you the completed shipments for each order, select the order_id and the count.
join the result of 1 and 2 with order on order id where (1.count = 2.count), select the name and the order_id.
You could try this
SELECT order_id FROM <orders>
WHERE order_id NOT IN (SELECT order_id FROM <shipments> WHERE status <> 'complete')
Even though, depending on your system I would consider adding a field in order table (effectively de-normalizing it, but benefits/drawbacks depend on how often you need this information) and update it with current order status.
If you need this information often, I might be worth it.
SELECT ship.order_id, ord.name
FROM shipments as ship
left join orders as ord on
ord.order_id = ship.order_id
where ship.status = 'complete'
Generally, the best way to do this is to have a level at the order itself that indicates whether or not the order is completely shipped.
But, this would work although it might not scale really well. To get it to scale better, you would have to do another join BACK to orders in the subqueries to limit the orders that you are looking through.
select order_id, name from
orders JOIN
(select order_id, count(*) from shipments where status = 'complete' group by order_id
INTERSECT
select order_id, count(*) from shipments group by order_id)
on order_id

MySQL - Finding out Balancing Figure From 2 Tables

I have 2 tables like this:
Stock Table
product_id bigint(20)
qty float
Sales Table
product_id bigint(20)
qty float
Sample Data
Stock Table
product_id---qty
1---10
2---11
3---20
4---50
1---10
3---10
Sales Table
product_id---qty
1---2
2---5
3---20
4---40
1---7
I want the following Output after running the Query
product_id---qty
1---11
2---6
3---10
4---10
Well, as spender ask I am trying to more clear the situation.
First of All, let's think that I store
10 quantity of product 1
11 quantity of product 2
20 quantity of product 3
50 quantity of product 4
10 quantity of product 1 (now I have total 20 of product 1)
10 quantity of product 3 (now I have total 30 of product 3)
Secondly, let's think that I sell
2 quantity of product 1
5 quantity of product 2
20 quantity of product 3
40 quantity of product 4
7 quantity of product 1 (now I have sold total 9 of product 1)
Thirdly, I want to know how much stock is now in my hand
11 quantity of product 1 (20-9 = 11)
6 quantity of product 2 (11-5 = 6)
10 quantity of product 3 (30-20 = 10)
10 quantity of product 4 (50-4 = 10)
My Question is: To find out this stock what is the Query?
Thanks in Advance for answering my question.
This answer works in Oracle - don't have MySql so can't test there
select product_id, sum(qty) from
(
select product_id, qty from stock
union all
select product_id, (-1 * qty) from sales
) as a
group by prod
You question is lacking detail and looks like it might even contain typos in the presented data. I'm going to make the assumption you are trying to calculate the diff between stock quantities and sales quantities, despite your data not actually supporting this (!!!). It looks like you require the following:
select
st.product_id,
sto.qty-st.qty
from
salesTable as st
join stockTable as sto on sto.product_id=st.product_id
Chris's answer is absolutely correct. But for the information I want to add this one which I found on NET.
SELECT tunion.product_id, (
(IFNULL((SELECT SUM(s.qty) FROM stock s WHERE s.product_id=tunion.product_id),0))-
(IFNULL((SELECT SUM(p.qty) FROM sales p WHERE p.product_id=tunion.product_id),0)))
AS quantity
FROM (SELECT DISTINCT s.product_id FROM stock s
UNION ALL SELECT DISTINCT p.product_id FROM sales p)
AS tunion GROUP BY tunion.product_id