IF/THEN logic in SQL statements - sql

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.

Related

Updating table and setting the field values to the result of a left join

I have a table Sales with the field Vendor ("Company A", "Company B", "Trader X"), and I have made a separate table called Vendors with two fields: VendorID and VendorName.
I want to delete the Vendor field in the table Sales and replace it with a VendorID field and fill the fill the field with the corresponding VendorIDs. In other words replace the names of the vendors in the Sales table with their ID from the Vendors table.
I have tried numerous solutions but they do not work. Here is one that I think will work. Some entries in the Sales table do not have any Vendors listed. There are 203 entries and the left join, when run on its own, returns all 203 vendors and the appropriate null values.
Update Sales
Set Sales.VendorID = (Select VendorID From Vendors v Left Join Sales s on
v.VendorName = s.Vendor);
When I run this I get a dialog box asking :
Enter Parameter Value
Or I get the error message :
Operation must use an updateable query
I am using MS Access 2016.
I think that you don't need a subquery, you could just use the UPDATE ... JOIN ... SET syntax, like :
UPDATE sales AS s
INNER JOIN Vendors AS v ON v.VendorName = s.Vendor
SET s.VendorID = v.VendorID

Multiple Conditions in SQL join, shopping cart example

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.

Query for Linking Purchase Orders with Sales Orders

I'm writing a report that includes sales order info + delivery notes. What I'm trying to do is add information from the purchase orders (ex. PO # & Price) table (I believe it is OPOR). How do I link this table to one or more of the tables I already have? Please see my query below:
SELECT o0.NumAtCard AS OrderNo
,i0.DocNum
,i0.TrackNo AS TrackingNo
,i0.CardName
, o0.DocNum AS DelivDoc
FROM ODLN d0
INNER JOIN DLN1 d1 ON d0.DocEntry = d1.DocEntry
LEFT OUTER JOIN INV1 i1 ON d1.TrgetEntry = i1.DocEntry
LEFT OUTER JOIN OINV i0 ON i1.DocEntry = i0.DocEntry
INNER JOIN ORDR o0 ON d1.BaseEntry = o0.DocEntry
INNER JOIN OITM itm ON i1.ItemCode = itm.ItemCode
WHERE o0.CANCELED = 'N' AND
i0.TrackNo IS NOT NULL
GROUP BY o0.NumAtCard
|,i0.DocNum
|,i0.TrackNo
,i0.CardName
,o0.DocNum
ORDER BY o0.NumAtCard
Ok so on the back and forth, it is clear the real question is about how to go about adding the information to the query.
A SQL consists of several major pieces in order:
The column list
The table/join specification (FROM and JOIN clauses)
The where section (WHERE...)
Aggregate rules (GROUP BY/Having)
Limit and offset (LIMIT/OFFSET)
In your case you need to start by identifying the information in the database you want to add, and how it relates to what you have already. So in this case you are going to:
Add the columns as necessary to the column list (the part between SELECT and FROM)
Add the table to the join list (via a LEFT JOIN, with the join condition following ON). So if you have a so_docnum field that matches the sales order docnum field it would be something like LEFT OUTER JOIN OPOR po ON po.so_docnum = o0.docnum)
Add anything needed to the GROUP BY clause (probably the fields you are adding from the PO).
However, your first step is to map out the data so that these steps can be executed because it is clear you don't have all the information you need to add it yet.

Sql tables need help please

I'm trying to build a sql query which worked for the previous one which had 2 tables and it was pretty straight forward. This one though, has been driving me insane for 6 hours now.
The problem I have is that the results are only displayed should ALL criteria match and I don't want that. I would like the field to result back blank if it does not have an entry in the database.
I have a table and I want to display the orderrefno. At this point I want to check to see if a delivery note has been created and if so, I want to then see if an invoice has been created. Then report back to the report with the numbers of each but if they don't exist, the. It should just have the order no and the others would be both blank or just the invoice would be blank, should a delivery note been done.
I've tried building a query in crystal using inner, left join, right join, full but if an invoice does NOT exist I want it to list the delivery no and order no, but it won't.
I can do this in datasources and master sources in delphi and v studio, but would like to do a sql because the other easy is slow.
My tables are
Project
Order
Calloff
Calltodeliverylink
Delivery
Deliverytoinvoicelink
Invoice
Tables are linked as follows.
Project.id is the main point of entry.
Then
Order.projectid -- project.id
Calloff.orderid -- order.id
Callofftodeliverylink.deliveryid -- call off.id
Delivery.id -- callofftodeliverylink.deliveryid
Deliverytoinvoicelink.deliveryid -- delivery.id
Invoice.id -- deliverytoinvoicelink.invoiceid
Many many thanks
EDIT:
Added Code. Sorry for FROM section being a mess. In crystal drew the linking fields and asked it to show me the query and this is what it gave me.
SELECT
"Projects"."ID", "Orders"."IntOrderNo", "Deliveries"."DeliveryNo", "Projects"."InternalRef",
"CallOffs"."ID", "Customers"."Name", "Contacts"."Name", "Invoices"."InvoiceNo"
FROM
{oj (((((("GNManager"."dbo"."Invoices" "Invoices" LEFT OUTER JOIN "GNManager"."dbo"."DeliveryToInvoiceLink" "DeliveryToInvoiceLink" ON "Invoices"."ID"="DeliveryToInvoiceLink"."InvoiceID") LEFT OUTER JOIN "GNManager"."dbo"."Deliveries" "Deliveries" ON "DeliveryToInvoiceLink"."DeliveryID"="Deliveries"."ID") LEFT OUTER JOIN "GNManager"."dbo"."CallOffToDeliveryLink" "CallOffToDeliveryLink" ON "Deliveries"."ID"="CallOffToDeliveryLink"."DeliveryID") LEFT OUTER JOIN "GNManager"."dbo"."CallOffs" "CallOffs" ON "CallOffToDeliveryLink"."CallOffID"="CallOffs"."ID") LEFT OUTER JOIN ("GNManager"."dbo"."Projects" "Projects" LEFT OUTER JOIN "GNManager"."dbo"."Orders" "Orders" ON "Projects"."ID"="Orders"."ProjectID") ON "CallOffs"."OrderID"="Orders"."ID") INNER JOIN "GNManager"."dbo"."Customers" "Customers" ON "Orders"."CustomerID"="Customers"."ID") INNER JOIN "GNManager"."dbo"."Contacts" "Contacts" ON "Orders"."ContactID"="Contacts"."ID"}
WHERE
"Projects"."InternalRef"='12/4169'
ORDER BY
"Projects"."InternalRef" DESC, "Orders"."IntOrderNo" DESC
The above statement does work and produces everything that I need, but only if Invoices has an entry. If invoices is blank, nothing gets displayed.
The order of the tables in your join statement is the issue. Invoices being the first table is the one that will drive the rest of the results.
If you need all orders associated with your projects, no matter if there are any invoices, here's what I would do. Please note that you need valid values in Projects, Orders, Customers and Contacts, but everything else could be null.
select
Projects.ID
,Orders.IntOrderNo
,Deliveries.DeliveryNo
,Projects.InternalRef
,CallOffs.ID
,Customers.Name
,Contacts.Name
,Invoices.InvoiceNo
from
Projects
join Orders on Orders.ProjectID = Projects.ID
join Customers on Orders.CustomerID = Customers.ID
join Contacts on Orders.ContactID = Contacts.ID
left join Callofs on Callofs.OrderID = Orders.ID
left join CallOffToDeliveryLink on CallOffToDeliveryLink.CallOffID = Callofs.ID
left join Deliveries on CallOffToDeliveryLink.DeliveryID = Deliveries.ID
left join DeliveryToInvoiceLink on DeliveryToInvoiceLink.DeliveryID = Deliveries.ID
left join Invoices on DeliveryToInvoiceLink.InvoiceID = Invoices.ID
where
Projects.InternalRef = '12/4169'
order by
Projects.InternalRef desc
,Orders.IntOrderNo desc

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.