SQL Server: Issue on Data Return - sql

As a novice SQL Server user, I ran into a problem that I did not know a solution to. I am trying to draw a master list of items and their cost. Some items have component items with their own cost, and those need to be called as well. However, whenever I try to include the component items, the query does not return items without components.
For example: I call 3 items from the query: A, B, and C. It displays their costs perfectly. However, I learn that Item C has a Component Item X. When I try to add a column for component item and it's cost, Items A and B are not returned in the query as they do not have a component item. I can't figure out why a NULL isn't placed when an item does not have a component item to accompany it.
Here is my query:
SELECT
T1.item_no, T2.item_cost, T1.component_item_no, T2.item_cost(2)
FROM
T1
INNER JOIN
T2 ON T2.item_no = T1.item_no
INNER JOIN
T2(2) ON T2.item_no = T1.component_item_no
I had to call T2 twice so I could call item cost for both the top level item as well as it's component.
Sample return data:

Change the INNER JOIN to LEFT JOIN for the component item table

Related

How to select items from child table based on values in parent table?

I have a table called tbl_PO and another table called tbl_PO_LineItems. In tbl_PO, the fields of relevance are 'PO#' and 'Status'. The 'Status' field has a few options, the one we're interested in for now is "Closed". Each PO has many line items, so there is a 1 to many relationship for the PO# in tbl_PO and the PO# in tbl_PO_LineItems. There is a field in tbl_PO_LineItems called 'LineNum', which is the line item number. There is another field called 'Code' which is a combination of the PO# and LineNum. I know this is a combined field but it makes the flow of data much easier in the rest of the database.
In a different table, call it tbl_table3, I want to be able to use an SQL statement along the lines of this:
SELECT Code FROM tbl_PO_LineItems WHERE tbl_PO.Status = 'Closed'
The problem is that there is no direct link from Code to any field in tbl_PO. I need to go through the PO# associated with that Code to get a Status value from tbl_PO for that PO#. How can I do this? I read up a bit on the JOIN command but I am not too comfortable with it.
Any help is appreciated.
Use an INNER JOIN:
SELECT t1.PO_num, t2.Code
FROM tbl_PO t1
INNER JOIN tbl_PO_LineItems t2
ON t1.PO_num = t2.PO_num
WHERE t1.Status = 'Closed'
I don't know how crazy I am about the combined column Code, but without more information I cannot make any suggestions for improvement.
Here are some options for you one with a join and one without. Let me know if this is what you're asking.(I wrote this off the top of my head but it should run)
SELECT * --you can choose your columns here
FROM tbl_PO AS PO, tbl_PO_LineItems AS LineItems
WHERE PO.ID = LineItems.PONumber
AND LineItems.Status = 'Closed
or with join
SELECT *
FROM tbl_PO AS PO
JOIN tbl_PO_LineItems AS LineItems
ON LineItems.PONumber = PO.ID
AND LineItems.Status = 'Closed

An Exclude Query with Link tables

I have two tables
**Item**
ID
...
**ShapeItem**
ID
ItemID
ShapeID
RegionID
(There are other columns and tables but they are not relevant to this question)
I can return all items that have a specific shape id in a specific region id successfully using an INNER JOIN
SELECT ID FROM Item INNER JOIN ShapeItem ON Item.ID = ShapeItem.ItemID WHERE ShapeID = 2
However I want to reverse this logic and return all items that DONT have a specific shape so my first thought was to do
SELECT ID FROM Item INNER JOIN ShapeItem ON Item.ID = ShapeItem.ItemID WHERE ShapeID <> 2
however this did not produce the required result, this returned all items that had a shape that was not the specific shape, but it did not account for those items that did not have any shapes at all.
My next thought was to use a LEFT JOIN but this returned every item with null values, (over 400,000)
I am currently stuck on this, can you suggest a way forward for me please?
Summary
I want to return all items that dont have a specific shape, including those items that are not referenced at all in the ShapeItem table.
SQL SERVER COMPACT 4.0
C#
Visual Studio 2012

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.

MS Access Distinct Records in Recordset

So, I once again seem to have an issue with MS Access being finicky, although it seems to also be an issue when trying similar queries in SSMS (SQL Server Management Studio).
I have a collection of tables, loosely defined as follows:
table widget_mfg { id (int), name (nvarchar) }
table widget { id (int), name (nvarchar), mfg_id (int) }
table widget_component { id (int), name (nvarchar), widget_id (int), component_id }
table component { id (int), name (nvarchar), ... } -- There are ~25 columns in this table
What I'd like to do is query the database and get a list of all components that a specific manufacturer uses. I've tried some of these queries:
SELECT c.*, wc.widget_id, w.mfg_id
FROM ((widget_component wc INNER JOIN widget w ON wc.widget_id = w.id)
INNER JOIN widget_manufacturer wm on w.mfg_id = wm.id)
INNER JOIN component c on c.id = wc.component_id
WHERE wm.id = 1
The previous example displays duplicates of any part that is contained in multiple widget_component lists for different widgets.
I've also tried doing:
SELECT DISTINCT c.id, c.name, wc.widget_id, w.mfg_id
FROM component c, widget_component wc, widget w, widget_manufacturer wm
WHERE wm.id=w.mfg_id AND wm.id = 1
This doesn't display anything at all. I was reading about sub-queries, but I do not understand how they work or how they would apply to my current application.
Any assistance in this would be beneficial.
As an aside, I am not very good with either MS Access or SQL in general. I know the basics, but not a lot beyond that.
Edit:
I just tried this code, and it works to get all the component.id's while limiting them to a single entry each. How do I go about using the results of this to get a list of all the rest of the component data (component.*) where the id's from the first part are used to select this data?
SELECT DISTINCT c.part_no
FROM component c, widget w, widget_component wc, widget_manufacturer wm
WHERE(((c.id=wc.component_id AND wc.widget_id=w.id AND w.mfg_id=wm.id AND wm.id=1)))
(P.S. this is probably not the best way to do this, but I am still learning SQL.)
What I'd like to do is query the database and get a list of all
components that a specific manufacturer uses
There are several ways to do this. IN is probably the easiest to write
SELECT c.*
FROM component c
WHERE c.id IN (SELECT c.component_id
FROM widget w
INNER JOIN widget_component c
ON w.id = c.widget_id
WHERE w.mfg_id = 123)
The IN sub query finds all the component ids that a specific manufacturer uses. The outer query then selects any component.id that is that result. It doesn't matter if its in there once or 1000 times it will only get the component record once.
The other ways of doing this are using an EXISTS sub query or using a join to the query (but then you do need to de-dup it)
It sounds like your component -to- widget relationship is one-to-many. Hence the duplicates. (i.e., the same component is used by more than one widget).
Your Select is almost OK --
SELECT c.*, wc.widget_id, w.mfg_id
but the wc.widget_id is causing the duplicates (per the assumption above).
So remove wc.widget_id from the SELECT, or else aggregate it (min, max, count, etc.). Removing is easier. If you agregate, remember to add a group by clause.
Try this:
SELECT DISTINCT c.*, w.mfg_id
Also -- FWIW, it's generally a better practice to use field names, instead of the *

Recursive SQL question

I need to find all the categories on the current level or below that have items, or have subcategories with items.
Categories have CategoryID, ParentCategoryID.
Items have a CategoryID.
I have most of the solution using a stored procedure:
AS
WITH get_cat_hier
AS
(
Select e.CategoryID, e.ParentCategoryID, From Categories AS e
where e.ParentCategoryId = #ParentCategoryId
union ALL
Select e.CategoryID, e.ParentCategoryID, From Categories e
inner join get_cat_hier AS ecte on ecte.CategoryID = e.ParentCategoryID
)
select DISTINCT e.CategoryID from Categories as e
inner join items as item on (item.CategoryID = e.CategoryID) -- *******Problem*****
where
(e.CategoryID in (select CategoryID FROM get_cat_hier AS CategoryID)
)
Unfortunately, this returns only the categories with items, and not categories with sub-categories with items. I need to replace the "item.CategoryID = e.CategoryID" with a recursive call somehow.
I'm not sure if this is a new solution or one that is in development. Doing this type of reporting is much much easier if you use nested sets to represent hierarchies. Joe Celko has some great articles on this topic.
I did request tracking system a number of years ago where there was a deep hierarchy for the chain of command. The reporting had to be for an individual and all their subordinates.
You should consider using nested sets and not using a parent pointer system.
http://en.wikipedia.org/wiki/Nested_set_model
Take out your where clause (I don't think it is needed)
Leave your item join and then also join to the get_cat_heir between your item table and categories table.
I think it's the CTE's anchor member that causes the wrong result set.
Its WHERE clause should actually be where e.CategoryId = #ParentCategoryId.