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

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

Related

Getting repeats of output, possibly doing a join wrong?

I'm having an issue where I'm getting some incorrect values in my output. I am binding the below highlighted table column with the circled column down the bottom. The service_id on the highlighted column is what is unique, but I need to bind the booking_id to retrieve the info (if that makes sense. What I end up getting is the top table where I get repeats, or the price is wrong. I should be getting only 5 lines in the top table.
Here's my code. I suspect I might be doing the join wrong?
SELECT bad.agent as Agents,
dog.SUPPLIER as SUPPLIER,
bad.status as TheStatus,
country.analysis_master1 as Country,
ftb.booking_actual_retail as BookingActualRetail,
ftb.Booking_Actual_Cost as BookingCost,
ftb.Booking_Actual_Retail_inc as BookingRetailINC,
fts.Service_Id,
fts.Service_Actual_Retail_inc as ServiceActualCostInc,
Product.SERVICE,
Product.SL_STATUS as SLSTATUS,
cat.name as Product2,
bad.LAST_SERVICE_DATE as Servicedate,
bad.LW_DATE as LWDATE,
ftb.Entered_Date as DATEENTERED,
ftb.Booking_Pax as PEOPLE,
ftb.Booking_Children as KIDS,
bad.TRAVELDATE as TRAVELDATE,
bad.FULL_REFERENCE
from BHD bad
inner join FTB on bad.FULL_REFERENCE = ftb.booking_reference
inner join FTS on FTB.Booking_Id = fts.Booking_Id
inner join DRM Country on bad.agent = country.code
inner join BSL Product on bad.BHD_ID = Product.BHD_ID
inner join SRV cat on Product.SERVICE = cat.CODE
inner join OPT dog on Product.OPT_ID = dog.OPT_ID
where bad.STATUS = 'IV' AND bad.FULL_REFERENCE = 'LTIT129488'
UPDATE:
Ok, so it looks like this join here causes the multiple outputs:
inner join FTS on FTB.Booking_Id = fts.Booking_Id
I have included the two tables, their headers, and sample data
You have somewhere put the join for the service or supplier in the wrong way.. Please check this line again.
inner join SRV cat on Product.SERVICE = cat.CODE
UPDATED SOLUTION :
As per your updated screenshots, I found the issue...
you have joined like this.
inner join FTB on bad.FULL_REFERENCE = ftb.booking_reference
In this join, your one table has single record against booking reference while another have multiple records against booking refrence. Thats why you are getting the multiple records in the output.
Remove this join and your problem will be solved. If you really want the data from this table then you can select in other way like using outer apply etc.

How to create a select for each row of table in ms sql server?

Suppose I have three tables:
How to select the CODE which IS ACTIVE (=1) from products table, the LINE NUM and DOCUMENT ID, that exist in table lines and is from document which is type KYT
for example the output should be something like:
Obviously it should start like
SELECT DOCUMENT ID
FROM [TABLE DOCUMENT]
WHERE TYPE='KYT'
And then for each row do something. I do not know how to accomplish this
Added the JOIN lines to join your 3 tables:
SELECT [PT].[CODE], [TL].[LINE NUM], [TD].[DOCUMENT ID]
FROM [TABLE DOCUMENT] as TD
JOIN [TABLE LINES] as TL
on TL.[DOCUMENT ID] = TD.[DOCUMENT ID]
JOIN [PRODUCTS TABLE] as PT
on PT.[PRODUCTS ID] = TL.[PRODUCT ID]
WHERE TYPE='KYT' AND PT.ISACTIVE = 1
What you're looking for is called a JOIN. Below is a join which selects all rows from all three tables. Play around with it.
JOINs are an essential MUST KNOW concept for Relation Database Management systems. They can be straight forward like this example, or can get pretty wild depending on what you need them to do. If youre going to continue working with SQL, you need to ge proficient with these.
SELECT *
FROM products p
INNER JOIN lines L ON p.[Products ID]=L.[Product ID]
INNER JOIN document d ON L.[Document ID]=d.[Document ID]
I’ll help you dissect this so you have a better idea of whats going on.
FROM products p
The ‘p’ is called an alias. It’s a way to shorten table names you might end up having to write multiple times plus helps with readability. You can alias however you want but I suggest making it meaningful like my example of using p for Products and so on and so forth.
INNER JOIN lines L ON p.[Products ID]=L.[Product ID]
The ON clause is used to “tie tables” together. This is normally a foreign key relationship in the schema. The column you are joining “ON” is the same data element. A basic example would be exactly like this one – product ID is in both tables and that’s how we relate the data from both tables together.

join a same table with different tables

I am wondering if anyone can help me, I have these tables:
tbl_search_history(id,fld_user_id,fld_username_fld_make_id,fld_model_id,fld_year_id,fld_category_id)
The fld_make is the name of the make:
tbl_make(id,fld_make)
The fld_model is the name of that model
tbl_model(id,fld_model)
The fld_year is the name of that year
tbl_year(id, fld_year)
The fld_category is the name of that category
tbl_category(id,fld_category)
Now I need to show a table in my page in which I need to have this fields: make, model, year, and category. I also want to know how can I have the make, model, year, and category names (instead of just the reference numbers from the tbl_search_history) in my page? Would you please give me a piece of code and a brief explanation?
Thanks in advance!
Your question is a bit unclear, but it sounds like a homework problem.
I will give you some pseudocode and references.
First off I would do some reading on JOINS.
If you are asking to get Column Names, see this SO question
I believe what you want to do is join your tables like so:
SELECT table1.desired_field, table2.desired_field2, table3.desired_field3
FROM table1
JOIN table2 ON table1.table2_id = table2.id
JOIN table3 ON table1.table3_id = table3.id
and so on.
SELECT
tbl_model.fld_make,
tbl_make.fld_model,
tbl_year.fld_year,
tbl_category.fld_category
FROM
tbl_search_history
INNER JOIN tbl_make ON tbl_search_history.fld_make_id = tbl_make.id
INNER JOIN tbl_model ON tbl_search_history.fld_model_id = tbl_model.id
INNER JOIN tbl_year ON tbl_search_history.fld_year_id = tbl_year.id
INNER JOIN tbl_category ON tbl_search_history.fld_category_id = tbl_category.id
Assuming that the search history table is the table that links all these other tables together. Also assuming that all of these tables have linked values (ie non-null id's in tbl_search_history) otherwise you'd need to use an OUTER JOIN.
What you want to do is to join with the make, model, year, and category tables using the ids you have in the tbl_search_history.
Something of this sort will give you want you want :
SELECT * FROM `tbl_search_history`
INNER JOIN `tbl_make`
ON tbl_search_history.fld_make_id = tbl_make.id
#keep going for model, year, and category tables using their respective ids.
Hope this helps!

Multiple Many-to-many bi-directional self-inner-joins without repeating whole query

I have a data model such that items can have many-to-many relationships with other items in the same table using a second table to define relationships. Let's call the primary table items, keyed by item_id and the relationships table item_assoc with columns item_id and other_item_id and assoc_type. Generally, you might use a union to pick up on relationships that may be defined in either direction in the item_assoc table, but you would wind up repeating other parts of the same query just to be sure to pick up associations defined in either direction.
Let's say that you're trying to put together a fairly complex query similar to the following where you want to find a list of items that have related items that COULD have associated cancellation items, but select those that do not have cancellation items:
select
orig.*
from items as orig
join item_assoc as orig2related
on orig.item_id = orig2related.item_id
join items as related
on orig2related.other_item_id = related.item_id
and orig2related.assoc_type = 'Related'
left join item_assoc as related2cancel
on related.item_id = related2cancel.item_id
left join items as cancel
on related2cancel.other_item_id = cancel.item_id
and related2cancel.assoc_type = 'Cancellation'
where cancel.item_id is null
This query obviously only picks up items whose relationships are defined in one direction. For a less complex query, I might solve this by adding a union at the bottom for every permutation of the reverse relationships, but I think that would make the query unnecessarily long and hard to understand.
Is there a way I can define both directions of each relationship without repeating the other parts of the query?
A UNION within item_assoc could help. Assuming you have a DB without a WITH clause you would have to define a view
CREATE VIEW bidirec_item_assoc AS
(
SELECT item_id, other_item_id, assoc_type, 1 as direction FROM item_assoc
UNION
SELECT other_item_id, item_id, assoc_type, 2 as direction FROM item_assoc
)
You can now use bidirec_item_assoc in your queries where you have used items_assoc before.
Edited Out: You could add columns for direction and relationtype, of course
Simplify, simplify, simplify: Don't involve tables in the query that aren't needed.
The following query should be equivalent to your sample query and more expressive of your intent:
select i.*
from items i
where not exists ( select *
from item_assoc r
join item_assoc c on c.item_id = r.item_id
and c.assoc_type = 'Cancellation'
where r.item_id = i.item_id
and r.assoc_type = 'Related'
)
It should select the set of items that aren't related to an item that has been cancelled. There's not need to join against the items table 3 times.
Further, your original query will have duplicate rows: every row in the first item table (orig) will be duplicated once for every related item.

List manipulating data from two tables content

I have these two tables
I would like to know how to do to list the product table: ProdID, Quantity, Name, Price
and table productUser: userId, State
The problem is that I need to also list all the information of product table and adding the UserId field with the same value and the state looks for a default value would be false ..
It is possible? could also, not to add the userId, State and drive it from my application code for assigning values​​. thanks
UPDATE:
If I understand your question correctly, you want to list specific fields from both tables but only when the child records match your criteria. If so, the query below would allow you to specify the userID and State.
SELECT p.prodId
,p.Quantity
,p.Name
,p.Price
,pu.userId
,pu.State
FROM Product p
INNER JOIN ProductUser pu
ON p.prodId = pu.prodId
WHERE pu.userID = #userID
AND pu.State = 0
--AND pu.State = #State
If my understanding is not correct, please post some sample table data and indicate which results you want returned.
Update to your update: I've defaulted State to zero in the query above. Followup question: do you want columns from both tables or are you trying to do an existence check against ProductUser to return just columns from Product?