Multiple Conditions in SQL join, shopping cart example - sql

Cart Example
I have two tables that I am working with related to a shopping cart. The first is the product table, and then the cart table. Note i have only included the relevant columns. I want to pull records from the product table that have not already been added to my cart. I can do it when there is only 1 memberid, but as you get more members, products will overlap so that is not going to work. I need to constrain my left outer join to include the member id also. This is what i have so far and this works. The issue is, how do i then constrain it to not show me products from the product table that have already been added to "my" cart which means to exclude where the memberid = 5
SELECT top 50
product.productid
FROM [shopping].[dbo].[product] with (NOLOCK)
LEFT OUTER JOIN cart with (NOLOCK) on product.productid = cart.productid
where 1=1
and cart.productid is null
My results should pull records 1 - 5 only.
I am clarifying what i want per Universus' comment. I want the query to display records from the product table that HAVE NOT already been added to cart. So i want the results to exclude records that are already in the cart for my memberid. This is not for an actual shopping cart application but i thought it would be best explained this way. I hope this clarifies the question.

What about this:
SELECT top 50 product.productid
FROM [shopping].[dbo].[product]
WHERE product.productid NOT IN (SELECT productID
FROM Card
WHERE MemberID = <current member ID value>
) A
Meaning "show me all products that were not selected by the current member". This is assuming that you clean the Cart table once the transaction is completed.

Related

How do I show all records from one table for each semi-related record in another?

This problem is extremely difficult to explain and I did not even know how to title it correctly so I do apologise about that in advance.
I have a view of products which is as follows:
Product
ProductId
ProductName
In my database, I have a ratecard table and a ratecard product table. A ratecard may be titled "Tier 1 Customers" and the corresponding RatecardProduct records would be prices for products for that particular ratecard. It may only contain prices for a few products and not all of them.
Ratecard
RatecardId
RatecardName
RatecardProduct
RatecardProductId
RatecardId
ProductId
UnitPrice
The problem is that I need to create a view which displays all products for all ratecards. If the ratecard / product combination does not have a corresponding unit price in my ratecardproduct table, it should show NULL or 0.
Imagine I have 10 products and 4 ratecards; the view would contain 40 records, even if the RatecardProduct table was completely empty
The reason I need to do this is because I am populating a gridview on viewing a ratecard and I do not want to have to do a round trip for each row to ascertain if there is a corresponding price.
Thank you so much in advance.
Generate all the rows. Then use left join to bring in the data:
select p.*, r.*, coalesce(rp.unitprice, 0) as unitprice
from products p cross join
ratecards r left join
ratecardproduct rp
on rp.productid = p.productid and rp.ratecardid = r.ratecardid;
Or don't use coalesce() if you want NULL.

Joining table issue with SQL Server 2008

I am using the following query to obtain some sales figures. The problem is that it is returning the wrong data.
I am joining together three tables tbl_orders tbl_orderitems tbl_payment. The tbl_orders table holds summary information, the tbl_orderitems holds the items ordered and the tbl_payment table holds payment information regarding the order. Multiple payments can be placed against each order.
I am trying to get the sum of the items sum(mon_orditems_pprice), and also the amount of items sold count(uid_orderitems).
When I run the following query against a specific order number, which I know has 1 order item. It returns a count of 2 and the sum of two items.
Item ProdTotal ProdCount
Westvale Climbing Frame 1198 2
This order has two payment records held in the tbl_payment table, which is causing the double count. If I remove the payment table join it reports the correct figures, or if I select an order which has a single payment it works as well. Am I missing something, I am tired!!??
SELECT
txt_orditems_pname,
SUM(mon_orditems_pprice) AS prodTotal,
COUNT(uid_orderitems) AS prodCount
FROM dbo.tbl_orders
INNER JOIN dbo.tbl_orderitems ON (dbo.tbl_orders.uid_orders = dbo.tbl_orderitems.uid_orditems_orderid)
INNER JOIN dbo.tbl_payment ON (dbo.tbl_orders.uid_orders = dbo.tbl_payment.uid_pay_orderid)
WHERE
uid_orditems_orderid = 61571
GROUP BY
dbo.tbl_orderitems.txt_orditems_pname
ORDER BY
dbo.tbl_orderitems.txt_orditems_pname
Any suggestions?
Thank you.
Drill down Table columns
dbo.tbl_payment.bit_pay_paid (1/0) Has this payment been paid, yes no
dbo.tbl_orders.bit_order_archive (1/0) Is this order archived, yes no
dbo.tbl_orders.uid_order_webid (integer) Web Shop's ID
dbo.tbl_orders.bit_order_preorder (1/0) Is this a pre-order, yes no
YEAR(dbo.tbl_orders.dte_order_stamp) (2012) Sales year
dbo.tbl_orders.txt_order_status (varchar) Is the order dispatched, awaiting delivery
dbo.tbl_orderitems.uid_orditems_pcatid (integer) Product category ID
It's a normal behavior, if you remove grouping clause you'll see that there really are 2 rows after joining and they both have 599 as a mon_orditems_pprice hence the SUM is correct. When there is a multiple match in any joined table the entire output row becomes multiple and the data that is being summed (or counted or aggregated in any other way) also gets summed multiple times. Try this:
SELECT txt_orditems_pname,
SUM(mon_orditems_pprice) AS prodTotal,
COUNT(uid_orderitems) AS prodCount
FROM dbo.tbl_orders
INNER JOIN dbo.tbl_orderitems ON (dbo.tbl_orders.uid_orders = dbo.tbl_orderitems.uid_orditems_orderid)
INNER JOIN
(
SELECT x.uid_pay_orderid
FROM dbo.tbl_payment x
GROUP BY x.uid_pay_orderid
) AS payments ON (dbo.tbl_orders.uid_orders = payments.uid_pay_orderid)
WHERE
uid_orditems_orderid = 61571
GROUP BY
dbo.tbl_orderitems.txt_orditems_pname
ORDER BY
dbo.tbl_orderitems.txt_orditems_pname
I don't know what data from tbl_payment you are using, are any of the columns from the SELECT list actually from tbl_payment? Why is tbl_payment being joined?

Applying calculations based on a number of criteria stored in separate tables?

What I need to create is a table containing "Rules" such as overriding prices and applying percentage increases to the price of stock.
For Example:
Sales Price is select from the table containing information about products, then the system needs to check another table to see if that Customer/Product/Product Category has any price rules set against it, such as percentage discount or set price to be overridden to.
How do I get access to first of all check if the customer in question exists in the table, then if the product exists and then if the category exists; and then apply the price change that is stored?
So far we have a PriceRules table that contains the headers:
RuleID | CustomerID | Product Code | Category | Price | Percentage | DateApplied | AppliedBy
The plan is to store the different variables in each column and then search based on the columns.
I'm sure this sounds really confusing so I will be around to answer queries as quickly as possible.
Thanks in advance,
Bob P
You can get these results using SQL JOINs:
SELECT ...
Product.ProductPrice as Price,
CustomerRules.ProductPriceRules as Rules
FROM Product
LEFT JOIN Customer
ON ...
LEFT JOIN CustomerRules
ON Product.ProductID = CustomerRules.ProductID
AND Customer.CustomerID = CustomerRules.CustomerID
LEFT JOIN will return ONLY matching results if any exist, if record does not exist all CustomerRules fields will contain NULL values

IF/THEN logic in SQL statements

Building a Shopping Cart app. Some products have options, some don't. I visitor can purchase a product either with or without the associate option if that product does have options.
I have the following JOIN statement to pull all the relative data for the shopping cart output:
SELECT tblshopping_cart.cart_id,
tblshopping_cart.session_id,
tblshopping_cart.product_id,
tblshopping_cart.product_qty,
tblshopping_cart.product_option,
tblproducts.product_title,
tblproducts.product_price,
tblproducts.product_sale_price_status,
tblproducts.product_sale_price,
tblproduct_options.option_text,
tblproduct_options.option_upcharge
FROM tblshopping_cart
INNER JOIN tblproducts ON tblshopping_cart.product_id = tblproducts.product_id
INNER JOIN tblproduct_options
ON tblshopping_cart.product_option = tblproduct_options.option_product_id
WHERE tblshopping_cart.session_id = '$session_id'
ORDER BY tblshopping_cart.product_qty ASC
It works if all the products in the cart all have associated tblshopping_cart.product_option's that exists in the tblproduct_options table. If a product doesn't have a valid option, it only returns those that do.
By default, any product added without an option gets added to the cart with the value of "0" for the product_option value. If the site user does choose an option, the option value gets added instead.
What I need to do is pull in the Options information (text and upcharge) IF that row has a valid option_product_id.
You should use a LEFT JOIN if you don't want to require your record set to have a relationship to product_option.
It would look like this:
LEFT JOIN tblproduct_options
ON tblshopping_cart.product_option = tblproduct_options.option_product_id
Instead of doing an INNER JOIN against tblproduct_options you should be doing a LEFT OUTER JOIN so that you get both products with and without an associated option.

SQL Syntax for Complex Scenario (Deals)

i have a complex query to be written but cannot figure it out
here are my tables
Sales --one row for each sale made in the system
SaleProducts --one row for each line in the invoice (similar to OrderDetails in NW)
Deals --a list of possible deals/offers that a sale may be entitled to
DealProducts --a list of quantities of products that must be purchased in order to get a deal
now im trying to make a query which will tell me for each sale which deals he may get
the relevant fields are:
Sales: SaleID (PK)
SaleProducts: SaleID (FK), ProductID (FK)
Deals: DealID (PK)
DealProducts: DealID(FK), ProductID(FK), Mandatories (int) for required qty
i believe that i should be able to use some sort of cross join or outer join, but it aint working
here is one sample (of about 30 things i tried)
SELECT DealProducts.DealID, DealProducts.ProductID, DealProducts.Mandatories,
viwSaleProductCount.SaleID, viwSaleProductCount.ProductCount
FROM DealProducts
LEFT OUTER JOIN viwSaleProductCount
ON DealProducts.ProductID = viwSaleProductCount.ProductID
GROUP BY DealProducts.DealID, DealProducts.ProductID, DealProducts.Mandatories,
viwSaleProductCount.SaleID, viwSaleProductCount.ProductCount
The problem is that it doesn't show any product deals that are not fulfilled (probably because of the ProductID join). i need that also sales that don't have the requirements show up, then I can filter out any SaleID that exists in this query where AmountBought < Mandatories etc
Thank you for your help
I'm not sure how well I follow your question (where does viwSaleProductCount fit in?) but it sounds like you will want an outer join to a subquery that returns a list of deals along with their associated products. I think it would go something like this:
Select *
From Sales s Inner Join SaleProducts sp on s.SaleID = sp.SaleID
Left Join (
Select *
From Deals d Inner Join DealProducts dp on d.DealID = dp.DealId
) as sub on sp.ProductID = sub.ProductID
You may need to add logic to ensure that deals don't appear twice, and of course replace * with the specific column names you'd need in all cases.
edit: if you don't actually need any information from the sale or deal tables, something like this could be used:
Select sp.SaleID, sp.ProductID, sp.ProductCount, dp.DealID, dp.Mandatories
From SaleProducts sp
Left Join DealProducts as dp on sp.ProductID = dp.ProductID
If you need to do grouping/aggregation on this result you will need to be careful to ensure that deals aren't counted multiple times for a given sale (Count Distinct may be appropriate, depending on your grouping). Because it is a Left Join, you don't need to worry about excluding sales that don't have a match in DealProducts.